Packages
Multi-surface application runtime for Elixir. One TEA module renders to terminal, browser (LiveView), SSH, and MCP (agents). 30+ widgets, flexbox + CSS grid, AI agent runtime, distributed swarm with CRDTs, time-travel debugging, session recording, sandboxed REPL, and agentic commerce.
Current section
Files
Jump to
Current section
Files
lib/raxol/plugins/manager.ex
defmodule Raxol.Plugins.Manager do
@moduledoc """
Plugin manager for Raxol.
Handles plugin lifecycle, registration, and state management.
"""
require Raxol.Core.Runtime.Log
alias Raxol.Plugins.{
Plugin,
PluginConfig
}
@type t :: %__MODULE__{
plugins: %{String.t() => Plugin.t()},
plugin_states: %{String.t() => any()},
plugin_config: PluginConfig.t(),
metadata: map(),
event_handler: function() | nil,
api_version: String.t(),
loaded_plugins: %{String.t() => Plugin.t()},
config: map(),
load_order: [String.t()]
}
defstruct [
:plugins,
:plugin_states,
:plugin_config,
:metadata,
:event_handler,
api_version: "1.0",
loaded_plugins: %{},
config: %{},
load_order: []
]
@doc """
Creates a new plugin manager with default configuration.
"""
def new(_opts \\ []) do
plugin_config = Raxol.Plugins.PluginConfig.new()
manager = %__MODULE__{
plugins: %{},
plugin_states: %{},
plugin_config: plugin_config,
metadata: %{},
event_handler: nil,
api_version: "1.0",
loaded_plugins: %{},
config: plugin_config
}
{:ok, manager}
end
@doc """
Gets a list of all loaded plugins.
"""
def list_plugins(%__MODULE__{} = manager) do
Map.values(manager.plugins)
end
@doc """
Gets a plugin by name.
"""
def get_plugin(%__MODULE__{} = manager, name) when is_binary(name) do
plugin_key = normalize_plugin_key(name)
Map.get(manager.plugins, plugin_key)
end
@doc """
Gets a plugin's state by name.
"""
def get_plugin_state(%__MODULE__{} = manager, name) when is_binary(name) do
plugin_key = normalize_plugin_key(name)
Map.get(manager.plugin_states, plugin_key)
end
@doc """
Sets a plugin's state by name.
"""
def set_plugin_state(%__MODULE__{} = manager, name, state)
when is_binary(name) do
plugin_key = normalize_plugin_key(name)
%{
manager
| plugin_states: Map.put(manager.plugin_states, plugin_key, state)
}
end
@doc """
Updates a plugin's state using a function.
"""
def update_plugin_state(%__MODULE__{} = manager, name, update_fun)
when is_binary(name) and is_function(update_fun, 1) do
plugin_key = normalize_plugin_key(name)
current_state = Map.get(manager.plugin_states, plugin_key, %{})
new_state = update_fun.(current_state)
%{
manager
| plugin_states: Map.put(manager.plugin_states, plugin_key, new_state)
}
end
@doc """
Gets the current API version of the plugin manager.
"""
def get_api_version(%__MODULE__{} = manager) do
manager.api_version
end
@doc """
Returns a map of loaded plugin names to plugin structs (for test compatibility).
"""
def loaded_plugins(%__MODULE__{} = manager) do
manager.loaded_plugins
end
@doc """
Updates the plugins map in the manager and keeps loaded_plugins in sync.
"""
def update_plugins(%__MODULE__{} = manager, plugins) when is_map(plugins) do
%{manager | plugins: plugins, loaded_plugins: plugins}
end
@doc """
Updates the configuration in the manager.
"""
def update_config(%__MODULE__{} = manager, config) do
%{manager | config: config}
end
@doc """
Loads a plugin module and initializes it. Delegates to Raxol.Plugins.Lifecycle.load_plugin/3.
"""
def load_plugin(%__MODULE__{} = manager, module) when is_atom(module) do
Raxol.Plugins.Lifecycle.load_plugin(manager, module)
end
@doc """
Loads a plugin module with specific configuration and initializes it.
Delegates to Raxol.Plugins.Lifecycle.load_plugin/3.
"""
def load_plugin(%__MODULE__{} = manager, module, config)
when is_atom(module) and is_map(config) do
Raxol.Plugins.Lifecycle.load_plugin(manager, module, config)
end
@doc """
Unloads a plugin by name and cleans up its resources.
Delegates to Raxol.Plugins.Lifecycle.unload_plugin/2.
"""
def unload_plugin(%__MODULE__{} = manager, plugin_name)
when is_binary(plugin_name) do
Raxol.Plugins.Lifecycle.unload_plugin(manager, plugin_name)
end
@doc """
Enables a plugin by name.
Delegates to Raxol.Plugins.Lifecycle.enable_plugin/2.
"""
def enable_plugin(%__MODULE__{} = manager, plugin_name)
when is_binary(plugin_name) do
Raxol.Plugins.Lifecycle.enable_plugin(manager, plugin_name)
end
@doc """
Disables a plugin by name.
Delegates to Raxol.Plugins.Lifecycle.disable_plugin/2.
"""
def disable_plugin(%__MODULE__{} = manager, plugin_name)
when is_binary(plugin_name) do
Raxol.Plugins.Lifecycle.disable_plugin(manager, plugin_name)
end
@doc """
Loads multiple plugins in the correct dependency order.
Delegates to Raxol.Plugins.Lifecycle.load_plugins/2.
"""
def load_plugins(%__MODULE__{} = manager, modules) when is_list(modules) do
Raxol.Plugins.Lifecycle.load_plugins(manager, modules)
end
# Helper to normalize plugin keys to strings
defp normalize_plugin_key(key) when is_binary(key), do: key
end