Plugin manager added. No more hand editing the settings file to enable and disable plugins. Hopefully less breakage. Updates to the local build and clean files for installing test builds.
This commit is contained in:
@ -70,6 +70,18 @@ make install || {
|
||||
echo -e "${GREEN}=== Build Complete ===${NC}"
|
||||
echo -e "${GREEN}Cthulhu installed to: ${LOCAL_PREFIX}${NC}"
|
||||
echo -e "${GREEN}Binary location: ${LOCAL_PREFIX}/bin/cthulhu${NC}"
|
||||
|
||||
# Ensure UI files are installed (fallback in case make install missed them)
|
||||
echo -e "${YELLOW}Ensuring UI files are installed...${NC}"
|
||||
mkdir -p "${LOCAL_PREFIX}/share/cthulhu/ui"
|
||||
if [[ ! -f "${LOCAL_PREFIX}/share/cthulhu/ui/cthulhu-setup.ui" ]]; then
|
||||
cp src/cthulhu/cthulhu-setup.ui "${LOCAL_PREFIX}/share/cthulhu/ui/" 2>/dev/null || true
|
||||
fi
|
||||
if [[ ! -f "${LOCAL_PREFIX}/share/cthulhu/ui/cthulhu-find.ui" ]]; then
|
||||
cp src/cthulhu/cthulhu-find.ui "${LOCAL_PREFIX}/share/cthulhu/ui/" 2>/dev/null || true
|
||||
fi
|
||||
echo -e "${GREEN}UI files confirmed.${NC}"
|
||||
|
||||
echo ""
|
||||
echo -e "${YELLOW}To run local Cthulhu:${NC}"
|
||||
echo -e " ${LOCAL_PREFIX}/bin/cthulhu"
|
||||
|
@ -57,15 +57,18 @@ uninstall_local() {
|
||||
# Remove Python modules
|
||||
rm -rf "${LOCAL_PREFIX}/lib/python"*/site-packages/cthulhu*
|
||||
|
||||
# Remove data files but preserve user settings
|
||||
# Remove data files but preserve user settings and UI files
|
||||
if [[ -d "${LOCAL_PREFIX}/share/cthulhu" ]]; then
|
||||
# Backup user settings if they exist
|
||||
# Backup user settings and UI files if they exist
|
||||
if [[ -f "${LOCAL_PREFIX}/share/cthulhu/user-settings.conf" ]]; then
|
||||
cp "${LOCAL_PREFIX}/share/cthulhu/user-settings.conf" /tmp/cthulhu-user-settings.backup
|
||||
fi
|
||||
if [[ -f "${LOCAL_PREFIX}/share/cthulhu/cthulhu-customizations.py" ]]; then
|
||||
cp "${LOCAL_PREFIX}/share/cthulhu/cthulhu-customizations.py" /tmp/cthulhu-customizations.backup
|
||||
fi
|
||||
if [[ -d "${LOCAL_PREFIX}/share/cthulhu/ui" ]]; then
|
||||
cp -r "${LOCAL_PREFIX}/share/cthulhu/ui" /tmp/cthulhu-ui.backup
|
||||
fi
|
||||
|
||||
# Remove the directory
|
||||
rm -rf "${LOCAL_PREFIX}/share/cthulhu"
|
||||
@ -78,6 +81,9 @@ uninstall_local() {
|
||||
if [[ -f /tmp/cthulhu-customizations.backup ]]; then
|
||||
mv /tmp/cthulhu-customizations.backup "${LOCAL_PREFIX}/share/cthulhu/cthulhu-customizations.py"
|
||||
fi
|
||||
if [[ -d /tmp/cthulhu-ui.backup ]]; then
|
||||
mv /tmp/cthulhu-ui.backup "${LOCAL_PREFIX}/share/cthulhu/ui"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Remove docs
|
||||
|
@ -138,6 +138,7 @@ src/cthulhu/plugins/HelloCthulhu/Makefile
|
||||
src/cthulhu/plugins/Clipboard/Makefile
|
||||
src/cthulhu/plugins/DisplayVersion/Makefile
|
||||
src/cthulhu/plugins/IndentationAudio/Makefile
|
||||
src/cthulhu/plugins/PluginManager/Makefile
|
||||
src/cthulhu/plugins/hello_world/Makefile
|
||||
src/cthulhu/plugins/self_voice/Makefile
|
||||
src/cthulhu/plugins/SimplePluginSystem/Makefile
|
||||
|
@ -1,4 +1,4 @@
|
||||
SUBDIRS = Clipboard DisplayVersion IndentationAudio hello_world self_voice ByeCthulhu HelloCthulhu SimplePluginSystem
|
||||
SUBDIRS = Clipboard DisplayVersion IndentationAudio PluginManager hello_world self_voice ByeCthulhu HelloCthulhu SimplePluginSystem
|
||||
|
||||
cthulhu_pythondir=$(pkgpythondir)/plugins
|
||||
|
||||
|
6
src/cthulhu/plugins/PluginManager/Makefile.am
Normal file
6
src/cthulhu/plugins/PluginManager/Makefile.am
Normal file
@ -0,0 +1,6 @@
|
||||
cthulhu_python_PYTHON = \
|
||||
__init__.py \
|
||||
plugin.info \
|
||||
plugin.py
|
||||
|
||||
cthulhu_pythondir=$(pkgpythondir)/plugins/PluginManager
|
14
src/cthulhu/plugins/PluginManager/__init__.py
Normal file
14
src/cthulhu/plugins/PluginManager/__init__.py
Normal file
@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2025 Stormux
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
"""PluginManager plugin package."""
|
||||
|
||||
from .plugin import PluginManager
|
||||
|
||||
__all__ = ['PluginManager']
|
8
src/cthulhu/plugins/PluginManager/plugin.info
Normal file
8
src/cthulhu/plugins/PluginManager/plugin.info
Normal file
@ -0,0 +1,8 @@
|
||||
name = PluginManager
|
||||
version = 1.0.0
|
||||
description = GUI interface for managing Cthulhu plugins - enable/disable plugins with checkboxes
|
||||
authors = Stormux <storm_dragon@stormux.org>
|
||||
website = https://git.stormux.org/storm/cthulhu
|
||||
copyright = Copyright 2025
|
||||
builtin = false
|
||||
hidden = false
|
421
src/cthulhu/plugins/PluginManager/plugin.py
Normal file
421
src/cthulhu/plugins/PluginManager/plugin.py
Normal file
@ -0,0 +1,421 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2025 Stormux
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
"""PluginManager plugin for Cthulhu - GUI interface for managing plugins."""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import configparser
|
||||
from pathlib import Path
|
||||
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk, GLib
|
||||
|
||||
from cthulhu.plugin import Plugin, cthulhu_hookimpl
|
||||
from cthulhu import debug
|
||||
from cthulhu import settings_manager
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
_settingsManager = settings_manager.getManager()
|
||||
|
||||
|
||||
class PluginManager(Plugin):
|
||||
"""Plugin that provides a GUI interface for managing other plugins."""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Initialize the PluginManager plugin."""
|
||||
super().__init__(*args, **kwargs)
|
||||
self._kb_binding = None
|
||||
self._dialog = None
|
||||
self._plugin_checkboxes = {}
|
||||
|
||||
logger.info("PluginManager plugin initialized")
|
||||
|
||||
@cthulhu_hookimpl
|
||||
def activate(self, plugin=None):
|
||||
"""Activate the PluginManager plugin."""
|
||||
if plugin is not None and plugin is not self:
|
||||
return
|
||||
|
||||
try:
|
||||
logger.info("=== PluginManager plugin activation starting ===")
|
||||
|
||||
# Register keybinding for opening plugin manager (Cthulhu+Shift+P)
|
||||
self._register_keybinding()
|
||||
|
||||
logger.info("PluginManager plugin activated successfully")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to activate PluginManager plugin: {e}")
|
||||
return False
|
||||
|
||||
@cthulhu_hookimpl
|
||||
def deactivate(self, plugin=None):
|
||||
"""Deactivate the PluginManager plugin."""
|
||||
if plugin is not None and plugin is not self:
|
||||
return
|
||||
|
||||
try:
|
||||
logger.info("=== PluginManager plugin deactivation starting ===")
|
||||
|
||||
# Close dialog if open
|
||||
if self._dialog:
|
||||
self._dialog.destroy()
|
||||
self._dialog = None
|
||||
|
||||
logger.info("PluginManager plugin deactivated successfully")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to deactivate PluginManager plugin: {e}")
|
||||
return False
|
||||
|
||||
def _register_keybinding(self):
|
||||
"""Register the Cthulhu+Shift+P keybinding for opening plugin manager."""
|
||||
try:
|
||||
if not self.app:
|
||||
logger.error("PluginManager: No app reference available for keybinding")
|
||||
return
|
||||
|
||||
# Register Cthulhu+Shift+P keybinding
|
||||
gesture_string = "kb:cthulhu+shift+p"
|
||||
description = "Open plugin manager"
|
||||
|
||||
self._kb_binding = self.registerGestureByString(
|
||||
self._open_plugin_manager,
|
||||
description,
|
||||
gesture_string
|
||||
)
|
||||
|
||||
if self._kb_binding:
|
||||
logger.info(f"PluginManager: Registered keybinding {gesture_string}")
|
||||
debug.printMessage(debug.LEVEL_INFO, f"PluginManager: Registered keybinding {gesture_string}", True)
|
||||
else:
|
||||
logger.error(f"PluginManager: Failed to register keybinding {gesture_string}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"PluginManager: Error registering keybinding: {e}")
|
||||
|
||||
def _open_plugin_manager(self, script, inputEvent=None):
|
||||
"""Open the plugin manager dialog."""
|
||||
try:
|
||||
debug.printMessage(debug.LEVEL_INFO, "PluginManager: Opening plugin manager dialog", True)
|
||||
|
||||
# Close existing dialog if open
|
||||
if self._dialog:
|
||||
self._dialog.destroy()
|
||||
|
||||
# Create new dialog
|
||||
self._create_dialog()
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"PluginManager: Error opening plugin manager: {e}")
|
||||
debug.printMessage(debug.LEVEL_INFO, f"PluginManager: Error opening dialog: {e}", True)
|
||||
return False
|
||||
|
||||
def _create_dialog(self):
|
||||
"""Create and show the plugin manager dialog."""
|
||||
try:
|
||||
# Create dialog window
|
||||
self._dialog = Gtk.Dialog(
|
||||
title="Cthulhu Plugin Manager",
|
||||
parent=None,
|
||||
flags=Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT
|
||||
)
|
||||
|
||||
# Set dialog properties
|
||||
self._dialog.set_default_size(400, 300)
|
||||
self._dialog.set_border_width(10)
|
||||
|
||||
# Add buttons
|
||||
self._dialog.add_button("Close", Gtk.ResponseType.CLOSE)
|
||||
|
||||
# Create main content area
|
||||
content_area = self._dialog.get_content_area()
|
||||
|
||||
# Add title label
|
||||
title_label = Gtk.Label()
|
||||
title_label.set_markup("<b>Available Plugins</b>")
|
||||
title_label.set_halign(Gtk.Align.CENTER)
|
||||
content_area.pack_start(title_label, False, False, 10)
|
||||
|
||||
# Add info label about PluginManager
|
||||
info_label = Gtk.Label()
|
||||
info_label.set_markup("<i>Note: PluginManager is always enabled and not shown here</i>")
|
||||
info_label.set_halign(Gtk.Align.CENTER)
|
||||
content_area.pack_start(info_label, False, False, 5)
|
||||
|
||||
# Create scrolled window for plugin list
|
||||
scrolled = Gtk.ScrolledWindow()
|
||||
scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
|
||||
scrolled.set_size_request(-1, 200)
|
||||
|
||||
# Create list box for plugins
|
||||
self._plugin_listbox = Gtk.ListBox()
|
||||
self._plugin_listbox.set_selection_mode(Gtk.SelectionMode.NONE)
|
||||
scrolled.add(self._plugin_listbox)
|
||||
|
||||
content_area.pack_start(scrolled, True, True, 0)
|
||||
|
||||
# Populate plugin list
|
||||
self._populate_plugin_list()
|
||||
|
||||
# Connect signals
|
||||
self._dialog.connect("response", self._on_dialog_response)
|
||||
|
||||
# Show dialog
|
||||
self._dialog.show_all()
|
||||
|
||||
debug.printMessage(debug.LEVEL_INFO, "PluginManager: Dialog created and shown", True)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"PluginManager: Error creating dialog: {e}")
|
||||
debug.printMessage(debug.LEVEL_INFO, f"PluginManager: Error creating dialog: {e}", True)
|
||||
|
||||
def _populate_plugin_list(self):
|
||||
"""Populate the plugin list with available plugins."""
|
||||
try:
|
||||
# Get available plugins
|
||||
available_plugins = self._discover_plugins()
|
||||
|
||||
# Get currently active plugins
|
||||
active_plugins = _settingsManager.getSetting('activePlugins') or []
|
||||
|
||||
debug.printMessage(debug.LEVEL_INFO, f"PluginManager: Found {len(available_plugins)} plugins", True)
|
||||
|
||||
# Clear existing checkboxes
|
||||
self._plugin_checkboxes.clear()
|
||||
|
||||
# Add each plugin as a checkbox (except PluginManager itself)
|
||||
for plugin_name, plugin_info in sorted(available_plugins.items()):
|
||||
# Skip PluginManager to prevent users from disabling plugin management
|
||||
if plugin_name == "PluginManager":
|
||||
continue
|
||||
|
||||
# Create row container
|
||||
row = Gtk.ListBoxRow()
|
||||
row.set_activatable(False)
|
||||
|
||||
# Create horizontal box for checkbox and info
|
||||
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10)
|
||||
hbox.set_border_width(5)
|
||||
|
||||
# Create checkbox
|
||||
checkbox = Gtk.CheckButton()
|
||||
checkbox.set_active(plugin_name in active_plugins)
|
||||
checkbox.connect("toggled", self._on_plugin_toggled, plugin_name)
|
||||
|
||||
# Create plugin info label
|
||||
info_text = f"<b>{plugin_name}</b>"
|
||||
if plugin_info.get('description'):
|
||||
info_text += f"\n{plugin_info['description']}"
|
||||
if plugin_info.get('version'):
|
||||
info_text += f" (v{plugin_info['version']})"
|
||||
|
||||
label = Gtk.Label()
|
||||
label.set_markup(info_text)
|
||||
label.set_halign(Gtk.Align.START)
|
||||
label.set_line_wrap(True)
|
||||
|
||||
# Pack widgets
|
||||
hbox.pack_start(checkbox, False, False, 0)
|
||||
hbox.pack_start(label, True, True, 0)
|
||||
|
||||
row.add(hbox)
|
||||
self._plugin_listbox.add(row)
|
||||
|
||||
# Store checkbox reference
|
||||
self._plugin_checkboxes[plugin_name] = checkbox
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"PluginManager: Error populating plugin list: {e}")
|
||||
debug.printMessage(debug.LEVEL_INFO, f"PluginManager: Error populating list: {e}", True)
|
||||
|
||||
def _discover_plugins(self):
|
||||
"""Discover all available plugins."""
|
||||
plugins = {}
|
||||
|
||||
try:
|
||||
# Get plugin system manager
|
||||
from cthulhu import plugin_system_manager
|
||||
|
||||
# Use existing plugin manager to get plugins
|
||||
if hasattr(plugin_system_manager, '_manager') and plugin_system_manager._manager:
|
||||
manager = plugin_system_manager._manager
|
||||
manager.rescanPlugins()
|
||||
|
||||
for plugin_info in manager.plugins:
|
||||
plugin_name = plugin_info.get_module_name()
|
||||
plugins[plugin_name] = {
|
||||
'name': plugin_name,
|
||||
'description': getattr(plugin_info, 'description', ''),
|
||||
'version': getattr(plugin_info, 'version', ''),
|
||||
'path': getattr(plugin_info, 'module_dir', '')
|
||||
}
|
||||
else:
|
||||
# Fallback: manually scan plugin directories
|
||||
plugins = self._manual_plugin_discovery()
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"PluginManager: Error in plugin discovery: {e}")
|
||||
debug.printMessage(debug.LEVEL_INFO, f"PluginManager: Plugin discovery error: {e}", True)
|
||||
# Fallback to manual discovery
|
||||
plugins = self._manual_plugin_discovery()
|
||||
|
||||
return plugins
|
||||
|
||||
def _manual_plugin_discovery(self):
|
||||
"""Manually discover plugins by scanning directories."""
|
||||
plugins = {}
|
||||
|
||||
try:
|
||||
# Get plugin directories
|
||||
from cthulhu.plugin_system_manager import PluginType
|
||||
|
||||
system_dir = PluginType.SYSTEM.get_root_dir()
|
||||
user_dir = PluginType.USER.get_root_dir()
|
||||
|
||||
for plugin_dir in [system_dir, user_dir]:
|
||||
if os.path.exists(plugin_dir):
|
||||
self._scan_plugin_directory(plugin_dir, plugins)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"PluginManager: Error in manual discovery: {e}")
|
||||
debug.printMessage(debug.LEVEL_INFO, f"PluginManager: Manual discovery error: {e}", True)
|
||||
|
||||
return plugins
|
||||
|
||||
def _scan_plugin_directory(self, directory, plugins):
|
||||
"""Scan a directory for plugins."""
|
||||
try:
|
||||
for item in os.listdir(directory):
|
||||
plugin_path = os.path.join(directory, item)
|
||||
if os.path.isdir(plugin_path):
|
||||
# Check for plugin.py and plugin.info
|
||||
plugin_py = os.path.join(plugin_path, "plugin.py")
|
||||
plugin_info_file = os.path.join(plugin_path, "plugin.info")
|
||||
|
||||
if os.path.exists(plugin_py):
|
||||
plugin_info = {'name': item, 'description': '', 'version': ''}
|
||||
|
||||
# Try to read plugin.info
|
||||
if os.path.exists(plugin_info_file):
|
||||
try:
|
||||
config = configparser.ConfigParser()
|
||||
config.read(plugin_info_file)
|
||||
|
||||
# Handle both INI-style and simple key=value format
|
||||
if config.sections():
|
||||
# INI-style format
|
||||
for section in config.sections():
|
||||
for key, value in config[section].items():
|
||||
if key.lower() in ['description', 'version']:
|
||||
plugin_info[key.lower()] = value
|
||||
else:
|
||||
# Simple key=value format
|
||||
with open(plugin_info_file, 'r') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if '=' in line and not line.startswith('#'):
|
||||
key, value = line.split('=', 1)
|
||||
key = key.strip().lower()
|
||||
value = value.strip()
|
||||
if key in ['description', 'version']:
|
||||
plugin_info[key] = value
|
||||
except Exception as info_e:
|
||||
debug.printMessage(debug.LEVEL_INFO, f"PluginManager: Error reading {plugin_info_file}: {info_e}", True)
|
||||
|
||||
plugins[item] = plugin_info
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"PluginManager: Error scanning directory {directory}: {e}")
|
||||
|
||||
def _on_plugin_toggled(self, checkbox, plugin_name):
|
||||
"""Handle plugin checkbox toggle."""
|
||||
try:
|
||||
is_active = checkbox.get_active()
|
||||
debug.printMessage(debug.LEVEL_INFO, f"PluginManager: Plugin {plugin_name} toggled to {'active' if is_active else 'inactive'}", True)
|
||||
|
||||
# Get current active plugins
|
||||
active_plugins = _settingsManager.getSetting('activePlugins') or []
|
||||
active_plugins = list(active_plugins) # Make a copy
|
||||
|
||||
# Update the list
|
||||
if is_active and plugin_name not in active_plugins:
|
||||
active_plugins.append(plugin_name)
|
||||
elif not is_active and plugin_name in active_plugins:
|
||||
active_plugins.remove(plugin_name)
|
||||
|
||||
# Save updated settings
|
||||
_settingsManager.setSetting('activePlugins', active_plugins)
|
||||
|
||||
# Save to disk using the backend directly
|
||||
try:
|
||||
# Get current general settings
|
||||
current_general = _settingsManager.getGeneralSettings()
|
||||
current_general['activePlugins'] = active_plugins
|
||||
|
||||
# Save using the backend
|
||||
backend = _settingsManager._backend
|
||||
if backend:
|
||||
backend.saveDefaultSettings(
|
||||
current_general,
|
||||
_settingsManager.getPronunciations(),
|
||||
_settingsManager.getKeybindings()
|
||||
)
|
||||
debug.printMessage(debug.LEVEL_INFO, "PluginManager: Settings saved to backend", True)
|
||||
else:
|
||||
debug.printMessage(debug.LEVEL_INFO, "PluginManager: No backend available for saving", True)
|
||||
|
||||
except Exception as save_e:
|
||||
debug.printMessage(debug.LEVEL_INFO, f"PluginManager: Error saving via backend: {save_e}", True)
|
||||
|
||||
debug.printMessage(debug.LEVEL_INFO, f"PluginManager: Updated active plugins: {active_plugins}", True)
|
||||
|
||||
# Show restart message
|
||||
self._show_restart_message()
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"PluginManager: Error toggling plugin {plugin_name}: {e}")
|
||||
debug.printMessage(debug.LEVEL_INFO, f"PluginManager: Error toggling {plugin_name}: {e}", True)
|
||||
|
||||
def _show_restart_message(self):
|
||||
"""Show a message that restart is needed to apply plugin changes."""
|
||||
if not hasattr(self, '_restart_message_shown'):
|
||||
try:
|
||||
# Get the content area of the existing dialog
|
||||
content_area = self._dialog.get_content_area()
|
||||
|
||||
# Add restart message if not already shown
|
||||
restart_label = Gtk.Label()
|
||||
restart_label.set_markup("<i>Restart Cthulhu to apply plugin changes</i>")
|
||||
restart_label.set_halign(Gtk.Align.CENTER)
|
||||
content_area.pack_end(restart_label, False, False, 10)
|
||||
restart_label.show()
|
||||
|
||||
self._restart_message_shown = True
|
||||
debug.printMessage(debug.LEVEL_INFO, "PluginManager: Added restart message to dialog", True)
|
||||
|
||||
except Exception as e:
|
||||
debug.printMessage(debug.LEVEL_INFO, f"PluginManager: Error showing restart message: {e}", True)
|
||||
|
||||
def _on_dialog_response(self, dialog, response_id):
|
||||
"""Handle dialog response (close button clicked)."""
|
||||
try:
|
||||
if response_id == Gtk.ResponseType.CLOSE:
|
||||
dialog.destroy()
|
||||
self._dialog = None
|
||||
debug.printMessage(debug.LEVEL_INFO, "PluginManager: Dialog closed", True)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"PluginManager: Error handling dialog response: {e}")
|
@ -413,4 +413,4 @@ presentChatRoomLast = False
|
||||
presentLiveRegionFromInactiveTab = False
|
||||
|
||||
# Plugins
|
||||
activePlugins = ['Clipboard', 'DisplayVersion', 'ByeCthulhu', 'HelloCthulhu', 'hello_world', 'self_voice', 'SimplePluginSystem']
|
||||
activePlugins = ['DisplayVersion', 'PluginManager', 'HelloCthulhu', 'ByeCthulhu']
|
||||
|
Reference in New Issue
Block a user