pub struct ExtensionManager { /* private fields */ }Expand description
Manages the lifecycle of all loaded extensions.
Implementations§
Source§impl ExtensionManager
impl ExtensionManager
Sourcepub fn new_with_tools(
hook_bus: Arc<HookBus>,
tools: Arc<RwLock<ToolRegistry>>,
) -> Self
pub fn new_with_tools( hook_bus: Arc<HookBus>, tools: Arc<RwLock<ToolRegistry>>, ) -> Self
Create a new manager with shared hook bus and tool registry.
Sourcepub fn bind_memory_backend(&mut self, exclusive: bool)
pub fn bind_memory_backend(&mut self, exclusive: bool)
Set once at host boot, before any extension can spawn.
Sourcepub async fn load(
&mut self,
id: &str,
manifest: &ExtensionManifest,
) -> Result<(), String>
pub async fn load( &mut self, id: &str, manifest: &ExtensionManifest, ) -> Result<(), String>
Load and start an extension from its manifest.
Sourcepub async fn load_with_cwd(
&mut self,
id: &str,
manifest: &ExtensionManifest,
cwd: Option<PathBuf>,
) -> Result<(), String>
pub async fn load_with_cwd( &mut self, id: &str, manifest: &ExtensionManifest, cwd: Option<PathBuf>, ) -> Result<(), String>
Load and start an extension from its manifest with a process cwd.
Sourcepub fn set_progressive_deferral(&mut self, enabled: bool)
pub fn set_progressive_deferral(&mut self, enabled: bool)
Enable Task 20 progressive spawn deferral (set at engine boot from the progressive-disclosure flag; default false keeps every legacy eager path byte-for-byte).
Sourcepub fn host_project_root(&self) -> Option<&str>
pub fn host_project_root(&self) -> Option<&str>
The HOST-OWNED trusted project root, discovered ONCE per manager
from the host’s own working directory via the canonical
agent_core project-scope walk (nearest .git/.synaps-project
marker, canonicalized). Recorded here so every extension load in
this manager’s lifetime sees one stable value. None when the
working directory is unavailable or cannot be canonicalized.
Sourcepub fn is_deferred(&self, id: &str) -> bool
pub fn is_deferred(&self, id: &str) -> bool
Whether one plugin id is currently deferred (any Task 20 class: tool-only, provider, hook/lifecycle, UI/sidecar, mixed — zero spawn). Boolean-only diagnostic: the underlying launch record (which holds resolved — potentially secret — config) is never exposed.
Sourcepub fn is_deferred_tool_only(&self, id: &str) -> bool
pub fn is_deferred_tool_only(&self, id: &str) -> bool
Compatibility alias for Self::is_deferred (Commit B name).
Sourcepub fn deferred_tool_only_count(&self) -> usize
pub fn deferred_tool_only_count(&self) -> usize
Number of retained deferred tool-only launch records (count-only diagnostic; never the records).
Sourcepub fn extension_runtime(&self) -> Arc<ExtensionRuntimeManager> ⓘ
pub fn extension_runtime(&self) -> Arc<ExtensionRuntimeManager> ⓘ
The SHARED extension runtime lease manager (Task 20 Commit B),
created on first use against this manager’s retained launch
records. The engine installs the same instance on the Runtime
(session capabilities + durable session-end scope); this manager
uses it for unload/reload lease revocation. Runtime acquisition —
spawn, re-validation, exact declaration matching — happens ONLY
inside that manager’s lease lifecycle.
Sourcepub fn extension_runtime_with_idle(
&self,
idle_max: Duration,
) -> Arc<ExtensionRuntimeManager> ⓘ
pub fn extension_runtime_with_idle( &self, idle_max: Duration, ) -> Arc<ExtensionRuntimeManager> ⓘ
As Self::extension_runtime, but the FIRST caller fixes the idle
reap bound (tests use short bounds; production uses the default).
Sourcepub async fn unload(&mut self, id: &str) -> Result<(), String>
pub async fn unload(&mut self, id: &str) -> Result<(), String>
Unload an extension — unsubscribe hooks and shut down the process.
A DEFERRED tool-only extension (Task 20) has no live handler: unloading it removes the retained launch record, deregisters its dormant catalog batch (advancing the catalog generation so stale grants cannot survive), and terminates every session’s runtime lease for the plugin.
Sourcepub async fn reload(
&mut self,
id: &str,
manifest: &ExtensionManifest,
cwd: Option<PathBuf>,
) -> Result<(), String>
pub async fn reload( &mut self, id: &str, manifest: &ExtensionManifest, cwd: Option<PathBuf>, ) -> Result<(), String>
Reload one extension by unloading any existing instance first, then loading the supplied manifest. If the new load fails, the previous instance remains unloaded so duplicate handlers cannot survive a broken reload.
Sourcepub fn discovery_state(&self) -> &DiscoveryState
pub fn discovery_state(&self) -> &DiscoveryState
Current process-level discovery state.
Sourcepub fn discovery_done(&self) -> Option<(Vec<String>, Vec<ExtensionLoadFailure>)>
pub fn discovery_done(&self) -> Option<(Vec<String>, Vec<ExtensionLoadFailure>)>
Some((loaded, failed)) once discovery has completed on this
manager; None while not started / running. Idempotence seam for
crate::extensions::loader::spawn_discover_and_load.
Sourcepub async fn shutdown_all(&mut self)
pub async fn shutdown_all(&mut self)
Shut down all extensions gracefully. Resets discovery so a later
discover_and_load on this manager walks the roots again.
Sourcepub fn shutdown_all_detached(manager: Arc<RwLock<Self>>) -> JoinHandle<()> ⓘ
pub fn shutdown_all_detached(manager: Arc<RwLock<Self>>) -> JoinHandle<()> ⓘ
Start shutting down all extensions in the background.
This is intended for process exit: the UI should not hang waiting for extension child processes to acknowledge shutdown. Dropping the join handle lets Tokio abort remaining work when the runtime exits.
Sourcepub fn handlers(&self) -> Vec<(String, Arc<dyn ExtensionHandler>)>
pub fn handlers(&self) -> Vec<(String, Arc<dyn ExtensionHandler>)>
Return Arc references to all running extension handlers, sorted by ID. Intended for background notification watchers that need to hold onto handlers beyond the lifetime of a manager lock.
Sourcepub async fn statuses(&self) -> Vec<ExtensionStatus>
pub async fn statuses(&self) -> Vec<ExtensionStatus>
Return health snapshots for all loaded extensions, sorted by ID.
Sourcepub fn providers(&self) -> Vec<&RegisteredProvider>
pub fn providers(&self) -> Vec<&RegisteredProvider>
Return registered provider metadata sorted by runtime id.
Sourcepub fn provider(&self, runtime_id: &str) -> Option<&RegisteredProvider>
pub fn provider(&self, runtime_id: &str) -> Option<&RegisteredProvider>
Return registered provider metadata by runtime id.
Sourcepub fn context_providers(&self) -> Vec<&RegisteredContextProviderDescriptor>
pub fn context_providers(&self) -> Vec<&RegisteredContextProviderDescriptor>
Return DORMANT context-provider descriptors declared by loaded
extensions, sorted by runtime address (task A6; mirrors
Self::providers for the UNRELATED model-provider catalog).
Pure catalog read — discovery/status spawn zero processes, and
holding a descriptor grants nothing.
Sourcepub fn context_provider(
&self,
provider_id: &ContextProviderId,
) -> Option<&RegisteredContextProviderDescriptor>
pub fn context_provider( &self, provider_id: &ContextProviderId, ) -> Option<&RegisteredContextProviderDescriptor>
Exact context-provider lookup by declared id (task A6; mirrors
Self::provider). Some iff EXACTLY ONE loaded extension
declares provider_id — zero matches and overlapping declarations
(the same id declared by multiple installed extensions) both
resolve to None, fail closed, no partial matches. Pure catalog
read — never spawns.
Sourcepub fn plugin_info(&self, id: &str) -> Option<&PluginInfo>
pub fn plugin_info(&self, id: &str) -> Option<&PluginInfo>
Return optional cached plugin info reported by info.get.
Sourcepub fn theme_tokens(&self) -> Vec<(String, BTreeMap<String, String>)>
pub fn theme_tokens(&self) -> Vec<(String, BTreeMap<String, String>)>
Manifest-declared theme tokens for every loaded extension, sorted by
extension ID (P19.2). Each entry is (plugin-id, token -> hex color);
the TUI namespaces these as ext.<plugin-id>.<token> when merging
into the active theme. Extensions without theme_tokens don’t appear.
Sourcepub fn user_action_handler(
&self,
id: &str,
) -> Result<Arc<dyn ExtensionHandler>, String>
pub fn user_action_handler( &self, id: &str, ) -> Result<Arc<dyn ExtensionHandler>, String>
Ask a plugin for its sidecar spawn arguments. Best-effort —
plugins that don’t host a sidecar (or pre-Phase-7 plugins that
haven’t implemented the RPC yet) return Err. Callers are
expected to treat that as “no overrides; use manifest defaults”.
Handler for explicit USER-triggered plugin APIs (sidecar spawn,
interactive commands, settings editors). Live extensions use their
running handler; a DEFERRED extension (Task 20) gets a lazy handler
whose first use acquires the shared per-plugin runtime lease — a
user action is a legitimate activation trigger. Discovery/search/
diagnostics never call this.
Sourcepub fn session_driver_handler(
&self,
id: &str,
) -> Result<Arc<dyn ExtensionHandler>, String>
pub fn session_driver_handler( &self, id: &str, ) -> Result<Arc<dyn ExtensionHandler>, String>
Resolve authority for an explicitly user-armed session driver without I/O.
Only successful eager loads retain validated permission metadata. Deferred,
unknown, failed, and unloaded instances fail closed; never acquire a lease.
Callers pin this Arc and compare it with Arc::ptr_eq on every timer and
before applying an async result. Drop the manager guard before plugin RPC.
Sourcepub fn has_session_drive(&self, id: &str) -> bool
pub fn has_session_drive(&self, id: &str) -> bool
(E-P8) Whether an eagerly-loaded extension holds the validated
session.drive permission. The TUI uses this to route a driver
plugin’s slash command to DriverStart (the actor front door)
instead of a plain interactive invoke. Fails closed for deferred,
unknown, or permission-less extensions.
pub async fn sidecar_spawn_args( &self, id: &str, ) -> Result<SidecarSpawnArgs, String>
Sourcepub async fn invoke_command(
&self,
id: &str,
command: &str,
args: Vec<String>,
request_id: &str,
sink: InvokeEventSink,
) -> Result<Value, String>
pub async fn invoke_command( &self, id: &str, command: &str, args: Vec<String>, request_id: &str, sink: InvokeEventSink, ) -> Result<Value, String>
Invoke an interactive plugin command on extension id. Streams
command.output (matching request_id) and task.* notifications
to sink. Returns the final JSON-RPC response value.
CP-11 fix-3: sink is the bounded, metered producer half of
crate::extensions::invoke_output::invoke_event_channel; the
caller MUST drive the matching collector concurrently with this
call (an awaited bounded send with no consumer would stall the
invocation loop until the 120 s timeout). Prefer
Self::invoke_command_collected, which wires that correctly.
Sourcepub async fn invoke_command_collected(
&self,
id: &str,
command: &str,
args: Vec<String>,
request_id: &str,
) -> (Result<Value, String>, InvokeOutputReport)
pub async fn invoke_command_collected( &self, id: &str, command: &str, args: Vec<String>, request_id: &str, ) -> (Result<Value, String>, InvokeOutputReport)
Invoke an interactive plugin command and collect its budgeted
output. This is THE production entry point for user-facing
surfaces: it joins the invocation with an eagerly concurrent
collector so hostile command.output floods are paced and capped
at production time (never parked unbounded), then returns the
final response alongside the retained events and exact
produced/consumed/retained/truncated/dropped accounting.
Dropping the returned future cancels the invocation, drops the sink, and releases the collector plus any blocked producers — no detached tasks are spawned.
pub async fn settings_editor_open( &self, id: &str, category: &str, field: &str, ) -> Result<Value, String>
pub async fn settings_editor_key( &self, id: &str, category: &str, field: &str, key: &str, ) -> Result<Value, String>
pub async fn settings_editor_commit( &self, id: &str, category: &str, field: &str, value: Value, ) -> Result<Value, String>
Sourcepub fn plugin_infos(&self) -> Vec<(&str, &PluginInfo)>
pub fn plugin_infos(&self) -> Vec<(&str, &PluginInfo)>
Return all cached plugin info sorted by extension id.
Sourcepub fn provider_summaries(&self) -> Vec<RegisteredProviderSummary>
pub fn provider_summaries(&self) -> Vec<RegisteredProviderSummary>
Return provider status summaries sorted by provider runtime id.
Sourcepub async fn capability_snapshots(&self) -> Vec<ExtensionCapabilitySnapshot>
pub async fn capability_snapshots(&self) -> Vec<ExtensionCapabilitySnapshot>
Unified capability snapshot per loaded extension, sorted by id.
Aggregates hook subscriptions, extension-provided tools, and registered
providers. future carries plugin-defined capability kinds and
capabilities land.
Sourcepub fn provider_tool_use_runtime_ids(&self) -> Vec<String>
pub fn provider_tool_use_runtime_ids(&self) -> Vec<String>
Return runtime ids of registered providers that declare at least one tool-use-capable model. Sorted by runtime id.
Sourcepub fn provider_trust_view(&self) -> BTreeMap<String, bool>
pub fn provider_trust_view(&self) -> BTreeMap<String, bool>
Return a runtime_id -> enabled map for every registered provider, computed
from the persisted trust state. Providers without an entry default to
enabled. If the trust state file is missing, all providers are reported
as enabled (default). If the file is corrupt, all providers are reported
as disabled (fail-closed) and a warning is logged.
Sourcepub fn config_diagnostics(&self, id: &str) -> Option<ExtensionConfigDiagnostics>
pub fn config_diagnostics(&self, id: &str) -> Option<ExtensionConfigDiagnostics>
Compute config diagnostics for a loaded extension by id.
Returns None if the extension is not loaded.
Sourcepub fn all_config_diagnostics(&self) -> Vec<ExtensionConfigDiagnostics>
pub fn all_config_diagnostics(&self) -> Vec<ExtensionConfigDiagnostics>
Diagnostics for all loaded extensions, sorted alphabetically by id.
Get the shared tool registry, when this manager was constructed with one.
Sourcepub async fn discover_and_load(
&mut self,
) -> (Vec<String>, Vec<ExtensionLoadFailure>)
pub async fn discover_and_load( &mut self, ) -> (Vec<String>, Vec<ExtensionLoadFailure>)
Discover and load all extensions from the user and project plugin directories.
Scans ~/.synaps-cli/plugins/*/.synaps-plugin/plugin.json and
./.synaps/plugins/*/.synaps-plugin/plugin.json for manifests that contain
an extension field. Project-local plugins override user plugins with the
same directory name.
Sourcepub async fn discover_and_load_with_progress<F>(
&mut self,
progress: F,
) -> (Vec<String>, Vec<ExtensionLoadFailure>)where
F: FnMut(ExtensionLoaderEvent),
pub async fn discover_and_load_with_progress<F>(
&mut self,
progress: F,
) -> (Vec<String>, Vec<ExtensionLoadFailure>)where
F: FnMut(ExtensionLoaderEvent),
Discover and load all extensions, invoking progress after each load
attempt. Used by the async UI loader to update startup toasts without
blocking first paint.
Auto Trait Implementations§
impl !Freeze for ExtensionManager
impl !RefUnwindSafe for ExtensionManager
impl !UnwindSafe for ExtensionManager
impl Send for ExtensionManager
impl Sync for ExtensionManager
impl Unpin for ExtensionManager
impl UnsafeUnpin for ExtensionManager
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
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§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.Source§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.Source§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.Source§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.