mindroot 9.3.0__py3-none-any.whl → 9.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mindroot/coreplugins/admin/__init__.py +3 -1
- mindroot/coreplugins/admin/agent_router.py +250 -7
- mindroot/coreplugins/admin/asset_manager.py +164 -0
- mindroot/coreplugins/admin/command_router.py +236 -1
- mindroot/coreplugins/admin/mcp_catalog_routes.py +156 -0
- mindroot/coreplugins/admin/mcp_publish_routes.py +450 -0
- mindroot/coreplugins/admin/mcp_registry_routes.py +495 -0
- mindroot/coreplugins/admin/mcp_routes.py +216 -0
- mindroot/coreplugins/admin/mod.py +62 -0
- mindroot/coreplugins/admin/oauth_callback_router.py +84 -0
- mindroot/coreplugins/admin/persona_handler.py +15 -6
- mindroot/coreplugins/admin/persona_router.py +158 -2
- mindroot/coreplugins/admin/plugin_manager.py +63 -0
- mindroot/coreplugins/admin/plugin_router_fixed.py +23 -0
- mindroot/coreplugins/admin/plugin_router_new_not_working.py +145 -0
- mindroot/coreplugins/admin/plugin_routes.py +114 -0
- mindroot/coreplugins/admin/registry_settings_routes.py +140 -0
- mindroot/coreplugins/admin/router.py +116 -15
- mindroot/coreplugins/admin/service_models.py +1 -1
- mindroot/coreplugins/admin/settings_router.py +1 -0
- mindroot/coreplugins/admin/static/css/admin-custom.css +357 -2
- mindroot/coreplugins/admin/static/css/dark.css +1 -0
- mindroot/coreplugins/admin/static/css/default.css +4 -0
- mindroot/coreplugins/admin/static/js/about-info.js +367 -0
- mindroot/coreplugins/admin/static/js/agent-form.js +83 -3
- mindroot/coreplugins/admin/static/js/api-key-script.js +307 -0
- mindroot/coreplugins/admin/static/js/mcp-manager.js +348 -0
- mindroot/coreplugins/admin/static/js/mcp-publisher.js +780 -0
- mindroot/coreplugins/admin/static/js/persona-editor.js +34 -5
- mindroot/coreplugins/admin/static/js/plugin-toggle.js +1 -1
- mindroot/coreplugins/admin/static/js/recommended-plugin-install.js +63 -0
- mindroot/coreplugins/admin/static/js/registry-auth-section.js +132 -0
- mindroot/coreplugins/admin/static/js/registry-manager-base.js +613 -0
- mindroot/coreplugins/admin/static/js/registry-manager-old.js +385 -0
- mindroot/coreplugins/admin/static/js/registry-manager-publish-old-delete.js +166 -0
- mindroot/coreplugins/admin/static/js/registry-manager.js +351 -0
- mindroot/coreplugins/admin/static/js/registry-publish-section.js +377 -0
- mindroot/coreplugins/admin/static/js/registry-search-section.js +400 -0
- mindroot/coreplugins/admin/static/js/registry-search-section.js.bak +3 -0
- mindroot/coreplugins/admin/static/js/registry-settings.js +69 -0
- mindroot/coreplugins/admin/static/js/registry-shared-services.js +857 -0
- mindroot/coreplugins/admin/static/js/registry-simple-sections.js +85 -0
- mindroot/coreplugins/admin/static/js/secure-widget-manager.js +438 -0
- mindroot/coreplugins/admin/static/logo.png +0 -0
- mindroot/coreplugins/admin/templates/admin.jinja2 +275 -110
- mindroot/coreplugins/agent/Assistant/agent.json +27 -11
- mindroot/coreplugins/agent/agent.py +2 -2
- mindroot/coreplugins/agent/command_parser.py +25 -10
- mindroot/coreplugins/agent/templates/system.jinja2 +0 -12
- mindroot/coreplugins/chat/__init__.py +4 -1
- mindroot/coreplugins/chat/router.py +132 -20
- mindroot/coreplugins/chat/router_dedup_patch.py +20 -0
- mindroot/coreplugins/chat/services.py +31 -1
- mindroot/coreplugins/chat/static/css/action-fix.css +32 -0
- mindroot/coreplugins/chat/static/css/admin-custom.css +5 -3
- mindroot/coreplugins/chat/static/css/dark.css +24 -3
- mindroot/coreplugins/chat/static/css/default.css +24 -3
- mindroot/coreplugins/chat/static/css/main.css +1 -0
- mindroot/coreplugins/chat/static/js/action.js +137 -60
- mindroot/coreplugins/chat/static/js/chat-history.js +3 -0
- mindroot/coreplugins/chat/static/js/chat.js +59 -16
- mindroot/coreplugins/chat/static/js/chat.js.diff +221 -0
- mindroot/coreplugins/chat/static/js/chatform.js +2 -2
- mindroot/coreplugins/chat/static/site.webmanifest +1 -1
- mindroot/coreplugins/chat/templates/chat.jinja2 +3 -3
- mindroot/coreplugins/chat/widget_manager.py +139 -0
- mindroot/coreplugins/chat/widget_routes.py +287 -0
- mindroot/coreplugins/check_list/inject/admin.jinja2 +1 -1
- mindroot/coreplugins/email/__init__.py +2 -0
- mindroot/coreplugins/email/email_provider.py +2 -2
- mindroot/coreplugins/email/mod.py +100 -0
- mindroot/coreplugins/email/services.py +5 -3
- mindroot/coreplugins/email/smtp_handler.py +9 -3
- mindroot/coreplugins/email/test_email_service.py +75 -0
- mindroot/coreplugins/env_manager/mod.py +61 -25
- mindroot/coreplugins/home/router.py +37 -2
- mindroot/coreplugins/home/static/imgs/logo.png +0 -0
- mindroot/coreplugins/home/static/imgs/logo.png.bak +0 -0
- mindroot/coreplugins/home/static/imgs/logo_teal.png +0 -0
- mindroot/coreplugins/home/static/imgs/logo_teal2.png +0 -0
- mindroot/coreplugins/home/static/imgs/logo_teal_detailed.png +0 -0
- mindroot/coreplugins/home/static/imgs/logo_teal_python.png +0 -0
- mindroot/coreplugins/home/templates/home.jinja2 +15 -6
- mindroot/coreplugins/index/indices/default/index.json +6 -6
- mindroot/coreplugins/jwt_auth/middleware.py +47 -2
- mindroot/coreplugins/jwt_auth/mod.py +40 -17
- mindroot/coreplugins/l8n/__init__.py +6 -0
- mindroot/coreplugins/l8n/debug_loader.py +85 -0
- mindroot/coreplugins/l8n/debug_middleware.py +74 -0
- mindroot/coreplugins/l8n/l8n_constants.py +19 -0
- mindroot/coreplugins/l8n/language_detection.py +183 -0
- mindroot/coreplugins/l8n/middleware.py +151 -0
- mindroot/coreplugins/l8n/mod.py +277 -0
- mindroot/coreplugins/l8n/monkey_patch_to_delete.py +186 -0
- mindroot/coreplugins/l8n/test_enhanced.py +298 -0
- mindroot/coreplugins/l8n/test_l8n.py +95 -0
- mindroot/coreplugins/l8n/test_l8n_standalone.py +251 -0
- mindroot/coreplugins/l8n/test_middleware.py +272 -0
- mindroot/coreplugins/l8n/utils.py +232 -0
- mindroot/coreplugins/mcp_/__init__.py +14 -0
- mindroot/coreplugins/mcp_/catalog_commands.py +328 -0
- mindroot/coreplugins/mcp_/catalog_manager.py +263 -0
- mindroot/coreplugins/mcp_/dynamic_commands.py +154 -0
- mindroot/coreplugins/mcp_/mcp_manager.py +1031 -0
- mindroot/coreplugins/mcp_/mod.py +367 -0
- mindroot/coreplugins/mcp_/oauth_storage.py +144 -0
- mindroot/coreplugins/mcp_/server_installer.py +79 -0
- mindroot/coreplugins/mcp_/setup.py +26 -0
- mindroot/coreplugins/mcp_/test_dynamic_commands.py +134 -0
- mindroot/coreplugins/mcp_/testmcpclient.py +92 -0
- mindroot/coreplugins/persona/mod.py +12 -7
- mindroot/coreplugins/signup/templates/signup.jinja2 +1 -1
- mindroot/coreplugins/subscriptions/__init__.py +1 -0
- mindroot/coreplugins/subscriptions/mod.py +14 -3
- mindroot/coreplugins/subscriptions/router.py +3 -0
- mindroot/coreplugins/user_service/__init__.py +1 -2
- mindroot/coreplugins/user_service/admin_init.py +1 -0
- mindroot/coreplugins/user_service/email_service.py +72 -17
- mindroot/coreplugins/user_service/mod.py +10 -2
- mindroot/coreplugins/user_service/router.py +2 -0
- mindroot/lib/auth/api_key.py +28 -0
- mindroot/lib/cli/plugins.py +94 -0
- mindroot/lib/plugins/default_plugin_manifest.json +20 -0
- mindroot/lib/plugins/installation.py +5 -5
- mindroot/lib/plugins/l8n_static_handler.py +225 -0
- mindroot/lib/plugins/loader.py +33 -3
- mindroot/lib/plugins/loader_with_l8n.py +281 -0
- mindroot/lib/plugins/manifest.py +236 -24
- mindroot/lib/providers/commands.py +3 -1
- mindroot/lib/route_decorators.py +5 -5
- mindroot/lib/templates.py +183 -11
- mindroot/lib/utils/merge_arrays.py +1 -1
- mindroot/migrate.py +39 -20
- mindroot/registry/data_access.py +1 -1
- mindroot/server.py +42 -13
- mindroot/server_missing_normal_args.py +197 -0
- mindroot/server_prev.py +173 -0
- {mindroot-9.3.0.dist-info → mindroot-9.5.0.dist-info}/METADATA +7 -2
- {mindroot-9.3.0.dist-info → mindroot-9.5.0.dist-info}/RECORD +144 -112
- mindroot/coreplugins/admin/static/favicon/about.txt +0 -6
- mindroot/coreplugins/admin/static/favicon/android-chrome-512x512.png +0 -0
- mindroot/coreplugins/admin/static/favicon/apple-touch-icon.png +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon-16x16.png +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon-32x32.png +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon.ico +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon_io (1)/about.txt +0 -6
- mindroot/coreplugins/admin/static/favicon/favicon_io (1)/android-chrome-192x192.png +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon_io (1)/android-chrome-512x512.png +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon_io (1)/apple-touch-icon.png +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon_io (1)/favicon-16x16.png +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon_io (1)/favicon-32x32.png +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon_io (1)/favicon.ico +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon_io (1)/site.webmanifest +0 -1
- mindroot/coreplugins/admin/static/favicon/logo.png +0 -0
- mindroot/coreplugins/admin/static/favicon/site.webmanifest +0 -1
- mindroot/coreplugins/admin/static/js/backup/agent-editor.js +0 -186
- mindroot/coreplugins/admin/static/js/backup/agent-form.js +0 -1133
- mindroot/coreplugins/admin/static/js/backup/agent-list.js +0 -94
- mindroot/coreplugins/chat/static/favicon/about.txt +0 -6
- mindroot/coreplugins/chat/static/favicon/android-chrome-192x192.png +0 -0
- mindroot/coreplugins/chat/static/favicon/android-chrome-512x512.png +0 -0
- mindroot/coreplugins/chat/static/favicon/apple-touch-icon.png +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon-16x16.png +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon-32x32.png +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon.ico +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon_io (1)/about.txt +0 -6
- mindroot/coreplugins/chat/static/favicon/favicon_io (1)/android-chrome-192x192.png +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon_io (1)/android-chrome-512x512.png +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon_io (1)/apple-touch-icon.png +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon_io (1)/favicon-16x16.png +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon_io (1)/favicon-32x32.png +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon_io (1)/favicon.ico +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon_io (1)/site.webmanifest +0 -1
- mindroot/coreplugins/chat/static/favicon/logo.png +0 -0
- mindroot/coreplugins/chat/static/favicon/site.webmanifest +0 -1
- mindroot/coreplugins/index/default.json +0 -76
- mindroot/coreplugins/user_service/file_trigger_service.py +0 -12
- mindroot/coreplugins/user_service/hooks.py +0 -23
- /mindroot/coreplugins/{admin/static/favicon/android-chrome-192x192.png → home/static/imgs/backuplogo.png} +0 -0
- {mindroot-9.3.0.dist-info → mindroot-9.5.0.dist-info}/WHEEL +0 -0
- {mindroot-9.3.0.dist-info → mindroot-9.5.0.dist-info}/entry_points.txt +0 -0
- {mindroot-9.3.0.dist-info → mindroot-9.5.0.dist-info}/licenses/LICENSE +0 -0
- {mindroot-9.3.0.dist-info → mindroot-9.5.0.dist-info}/top_level.txt +0 -0
|
@@ -282,12 +282,12 @@ async def install_recommended_plugins(agent_name, context=None):
|
|
|
282
282
|
for plugin_source in recommended_plugins:
|
|
283
283
|
for index in available_indices:
|
|
284
284
|
for plugin in index.get('plugins', []):
|
|
285
|
-
remote_source = plugin.get('remote_source'
|
|
286
|
-
print(f"Checking
|
|
285
|
+
remote_source = plugin.get('remote_source') or plugin.get('github_url') or plugin.get('source')
|
|
286
|
+
print(f"Checking index plugin {remote_source} against recommended {plugin_source}")
|
|
287
287
|
if remote_source == plugin_source:
|
|
288
|
-
if 'github.com/' in remote_source:
|
|
289
|
-
github_path =
|
|
290
|
-
print(f"Extracted GitHub path for {
|
|
288
|
+
if remote_source and 'github.com/' in remote_source:
|
|
289
|
+
github_path = remote_source.split('github.com/')[1]
|
|
290
|
+
print(f"Extracted GitHub path for {plugin_source}: {github_path}")
|
|
291
291
|
plugin_sources[plugin_source] = github_path
|
|
292
292
|
elif remote_source:
|
|
293
293
|
plugin_sources[plugin_source] = remote_source
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import re
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from fastapi import Request, Response
|
|
5
|
+
from fastapi.staticfiles import StaticFiles
|
|
6
|
+
from starlette.responses import FileResponse
|
|
7
|
+
from starlette.types import Scope, Receive, Send
|
|
8
|
+
#from lib.utils.debug import debug_box
|
|
9
|
+
import sys
|
|
10
|
+
import traceback
|
|
11
|
+
|
|
12
|
+
# Import l8n translation functions
|
|
13
|
+
try:
|
|
14
|
+
from mindroot.coreplugins.l8n.utils import replace_placeholders, extract_plugin_root, get_localized_file_path, load_plugin_translations
|
|
15
|
+
from mindroot.coreplugins.l8n.middleware import get_request_language
|
|
16
|
+
from mindroot.coreplugins.l8n.language_detection import get_fallback_language
|
|
17
|
+
L8N_AVAILABLE = True
|
|
18
|
+
except ImportError as e:
|
|
19
|
+
trace = traceback.format_exc()
|
|
20
|
+
print(f"L8n not available for static files: {e}\n{trace}")
|
|
21
|
+
L8N_AVAILABLE = False
|
|
22
|
+
sys.exit(1)
|
|
23
|
+
|
|
24
|
+
class TranslatedStaticFiles(StaticFiles):
|
|
25
|
+
"""Custom StaticFiles handler that applies l8n translations to JavaScript files."""
|
|
26
|
+
|
|
27
|
+
def __init__(self, *, directory: str, plugin_name: str = None, **kwargs):
|
|
28
|
+
super().__init__(directory=directory, **kwargs)
|
|
29
|
+
self.plugin_name = plugin_name
|
|
30
|
+
self.directory_path = Path(directory)
|
|
31
|
+
|
|
32
|
+
def get_current_language(self, request: Request) -> str:
|
|
33
|
+
"""Get the current language for the request."""
|
|
34
|
+
print("Getting current language for static file request...")
|
|
35
|
+
if not L8N_AVAILABLE:
|
|
36
|
+
print("WARNING: L8n not available, defaulting to 'en'.")
|
|
37
|
+
return 'en'
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
# Try to get from request state first (set by middleware)
|
|
41
|
+
if hasattr(request.state, 'language'):
|
|
42
|
+
print(f"Using language from request state: {request.state.language}")
|
|
43
|
+
return request.state.language
|
|
44
|
+
|
|
45
|
+
# Fallback to l8n middleware function
|
|
46
|
+
lang = get_request_language()
|
|
47
|
+
return get_fallback_language(lang) if lang else 'en'
|
|
48
|
+
except Exception as e:
|
|
49
|
+
print(f"Error getting language for static file: {e}")
|
|
50
|
+
return 'en'
|
|
51
|
+
|
|
52
|
+
def should_translate_file(self, file_path: Path) -> bool:
|
|
53
|
+
"""Check if a file should be translated."""
|
|
54
|
+
if not L8N_AVAILABLE:
|
|
55
|
+
print("L8n not available, skipping translation check.")
|
|
56
|
+
return False
|
|
57
|
+
|
|
58
|
+
# show suffix
|
|
59
|
+
print(f"Checking if file should be translated: {file_path} suffix is {file_path.suffix}")
|
|
60
|
+
# Only translate JavaScript files for now
|
|
61
|
+
return file_path.suffix.lower() in ['.js', '.mjs']
|
|
62
|
+
|
|
63
|
+
def apply_translations_to_js(self, content: str, language: str, file_path: str) -> str:
|
|
64
|
+
"""Apply translations to JavaScript content.
|
|
65
|
+
|
|
66
|
+
This looks for __TRANSLATE_key__ placeholders in JS files and replaces them
|
|
67
|
+
with translated strings. If translations are missing, returns None to
|
|
68
|
+
signal that the original file should be served instead.
|
|
69
|
+
"""
|
|
70
|
+
if not L8N_AVAILABLE or not content:
|
|
71
|
+
return content
|
|
72
|
+
|
|
73
|
+
try:
|
|
74
|
+
# Use the l8n replace_placeholders function
|
|
75
|
+
translated_content = replace_placeholders(content, language, file_path)
|
|
76
|
+
|
|
77
|
+
# If None is returned, translations are incomplete
|
|
78
|
+
if translated_content is None:
|
|
79
|
+
print(f"L8n: Missing translations for JS file, will serve original: {file_path}")
|
|
80
|
+
return None
|
|
81
|
+
|
|
82
|
+
return translated_content
|
|
83
|
+
except Exception as e:
|
|
84
|
+
print(f"Error applying translations to JS file {file_path}: {e}")
|
|
85
|
+
return None # Fallback to original file on error
|
|
86
|
+
|
|
87
|
+
async def get_response(self, path: str, scope: Scope) -> Response:
|
|
88
|
+
"""Override to add translation support for JavaScript files."""
|
|
89
|
+
try:
|
|
90
|
+
# Get the full file path
|
|
91
|
+
full_path = self.directory_path / path
|
|
92
|
+
|
|
93
|
+
# Check if file exists and should be translated
|
|
94
|
+
print(f"l8n Checking static file: {full_path}")
|
|
95
|
+
if full_path.exists() and self.should_translate_file(full_path):
|
|
96
|
+
print(f"l8n Translating static file: {full_path}")
|
|
97
|
+
# Create a request object to get language
|
|
98
|
+
request = Request(scope)
|
|
99
|
+
current_language = self.get_current_language(request)
|
|
100
|
+
print(f"[UPDATE] l8n Current language for static file: {current_language}")
|
|
101
|
+
|
|
102
|
+
localized_path = get_localized_file_path(str(full_path))
|
|
103
|
+
|
|
104
|
+
# Check if localized file exists
|
|
105
|
+
if localized_path.exists():
|
|
106
|
+
# Read the localized file content
|
|
107
|
+
with open(localized_path, "r", encoding="utf-8") as f:
|
|
108
|
+
content = f.read()
|
|
109
|
+
|
|
110
|
+
# Apply translations
|
|
111
|
+
translated_content = self.apply_translations_to_js(
|
|
112
|
+
content, current_language, str(localized_path)
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
# If translations are complete, serve translated content
|
|
116
|
+
if translated_content is not None:
|
|
117
|
+
print(f"l8n: Serving translated JS file: {full_path}")
|
|
118
|
+
return Response(
|
|
119
|
+
content=translated_content,
|
|
120
|
+
media_type="application/javascript",
|
|
121
|
+
headers={
|
|
122
|
+
"Cache-Control": "no-cache, no-store, must-revalidate",
|
|
123
|
+
"Pragma": "no-cache",
|
|
124
|
+
"Expires": "0"
|
|
125
|
+
}
|
|
126
|
+
)
|
|
127
|
+
else:
|
|
128
|
+
print(f"l8n: Translations incomplete, serving original JS file: {full_path}")
|
|
129
|
+
else:
|
|
130
|
+
print(f"l8n: No localized version found, serving original JS file: {full_path}")
|
|
131
|
+
# For non-JS files or when translation is not available, use default behavior
|
|
132
|
+
print(f"l8n Serving static file without translation: {full_path}")
|
|
133
|
+
return await super().get_response(path, scope)
|
|
134
|
+
|
|
135
|
+
except Exception as e:
|
|
136
|
+
trace = traceback.format_exc()
|
|
137
|
+
print(f"Error in translated static file handler: {e}\n{trace}")
|
|
138
|
+
# Fallback to default behavior on error
|
|
139
|
+
return await super().get_response(path, scope)
|
|
140
|
+
|
|
141
|
+
def mount_translated_static_files(app, plugin_name: str, category: str):
|
|
142
|
+
"""Mount plugin static files with translation support.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
app (FastAPI): The FastAPI application instance
|
|
146
|
+
plugin_name (str): Name of the plugin
|
|
147
|
+
category (str): Plugin category ('core' or 'installed')
|
|
148
|
+
"""
|
|
149
|
+
from .paths import get_plugin_path
|
|
150
|
+
|
|
151
|
+
# debug_box(f"Mounting translated static files for plugin: {plugin_name} in category: {category}")
|
|
152
|
+
|
|
153
|
+
plugin_dir = get_plugin_path(plugin_name)
|
|
154
|
+
if not plugin_dir:
|
|
155
|
+
return
|
|
156
|
+
|
|
157
|
+
dir_name = os.path.basename(plugin_dir)
|
|
158
|
+
|
|
159
|
+
if category != 'core':
|
|
160
|
+
static_path = os.path.join(plugin_dir, 'src', dir_name, 'static')
|
|
161
|
+
if not os.path.exists(static_path):
|
|
162
|
+
static_path = os.path.join(plugin_dir, 'static')
|
|
163
|
+
else:
|
|
164
|
+
static_path = os.path.join(plugin_dir, 'static')
|
|
165
|
+
|
|
166
|
+
if os.path.exists(static_path):
|
|
167
|
+
# Use our custom TranslatedStaticFiles instead of regular StaticFiles
|
|
168
|
+
app.mount(
|
|
169
|
+
f"/{dir_name}/static",
|
|
170
|
+
TranslatedStaticFiles(directory=static_path, plugin_name=plugin_name),
|
|
171
|
+
name=f"/{dir_name}/static"
|
|
172
|
+
)
|
|
173
|
+
print(f"Mounted translated static files for plugin: {plugin_name} at {static_path}")
|
|
174
|
+
#debug_box(f"Mounted translated static files for plugin: {plugin_name} at {static_path}")
|
|
175
|
+
else:
|
|
176
|
+
print(f"No static files found for plugin: {plugin_name}. Searched in {static_path}")
|
|
177
|
+
#debug_box(f"No static files found for plugin: {plugin_name}. Searched in {static_path}")
|
|
178
|
+
|
|
179
|
+
# JavaScript-specific translation helpers
|
|
180
|
+
def create_js_translation_object(translations: dict) -> str:
|
|
181
|
+
"""Create a JavaScript object containing translations.
|
|
182
|
+
|
|
183
|
+
This can be injected into JS files to provide client-side translation support.
|
|
184
|
+
|
|
185
|
+
Args:
|
|
186
|
+
translations: Dictionary of translation key-value pairs
|
|
187
|
+
|
|
188
|
+
Returns:
|
|
189
|
+
JavaScript code defining a translation object
|
|
190
|
+
"""
|
|
191
|
+
import json
|
|
192
|
+
|
|
193
|
+
# Safely serialize translations to JavaScript
|
|
194
|
+
js_translations = json.dumps(translations, ensure_ascii=False)
|
|
195
|
+
|
|
196
|
+
return f"""
|
|
197
|
+
// Auto-generated translation object
|
|
198
|
+
window.MINDROOT_TRANSLATIONS = {js_translations};
|
|
199
|
+
|
|
200
|
+
// Helper function to get translations
|
|
201
|
+
window.translate = function(key, fallback) {{
|
|
202
|
+
return window.MINDROOT_TRANSLATIONS[key] || fallback || key;
|
|
203
|
+
}};
|
|
204
|
+
|
|
205
|
+
// Alias for shorter usage
|
|
206
|
+
window.t = window.translate;
|
|
207
|
+
"""
|
|
208
|
+
|
|
209
|
+
def inject_translations_into_js(content: str, translations: dict) -> str:
|
|
210
|
+
"""Inject translation object into JavaScript content.
|
|
211
|
+
|
|
212
|
+
This prepends translation definitions to JS files.
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
content: Original JavaScript content
|
|
216
|
+
translations: Translation dictionary
|
|
217
|
+
|
|
218
|
+
Returns:
|
|
219
|
+
JavaScript content with translations injected
|
|
220
|
+
"""
|
|
221
|
+
if not translations:
|
|
222
|
+
return content
|
|
223
|
+
|
|
224
|
+
translation_js = create_js_translation_object(translations)
|
|
225
|
+
return translation_js + "\n\n" + content
|
mindroot/lib/plugins/loader.py
CHANGED
|
@@ -11,6 +11,15 @@ from .manifest import list_enabled, load_plugin_manifest
|
|
|
11
11
|
from .installation import check_plugin_dependencies
|
|
12
12
|
from mindroot.lib.utils.debug import debug_box
|
|
13
13
|
|
|
14
|
+
# Try to import l8n static handler
|
|
15
|
+
try:
|
|
16
|
+
from .l8n_static_handler import mount_translated_static_files
|
|
17
|
+
L8N_STATIC_AVAILABLE = True
|
|
18
|
+
except ImportError as e:
|
|
19
|
+
print(f"L8n static handler not available: {e}")
|
|
20
|
+
debug_box("L8n static handler not available, falling back to regular static files")
|
|
21
|
+
L8N_STATIC_AVAILABLE = False
|
|
22
|
+
|
|
14
23
|
app_instance = None
|
|
15
24
|
|
|
16
25
|
def load_middleware(app, plugin_name, plugin_path, category):
|
|
@@ -67,13 +76,23 @@ def load_middleware(app, plugin_name, plugin_path, category):
|
|
|
67
76
|
print(f"No middleware loaded for plugin: {plugin_name}")
|
|
68
77
|
|
|
69
78
|
def mount_static_files(app, plugin_name, category):
|
|
70
|
-
"""Mount plugin static files if
|
|
79
|
+
"""Mount plugin static files with translation support if available.
|
|
71
80
|
|
|
72
81
|
Args:
|
|
73
82
|
app (FastAPI): The FastAPI application instance
|
|
74
83
|
plugin_name (str): Name of the plugin
|
|
75
84
|
category (str): Plugin category ('core' or 'installed')
|
|
76
85
|
"""
|
|
86
|
+
# Try to use translated static files first if l8n is available
|
|
87
|
+
if L8N_STATIC_AVAILABLE:
|
|
88
|
+
try:
|
|
89
|
+
mount_translated_static_files(app, plugin_name, category)
|
|
90
|
+
return
|
|
91
|
+
except Exception as e:
|
|
92
|
+
print(f"Could not mount translated static files for {plugin_name}: {e}")
|
|
93
|
+
print("Falling back to regular static file mounting")
|
|
94
|
+
|
|
95
|
+
# Fallback to regular static file mounting
|
|
77
96
|
plugin_dir = get_plugin_path(plugin_name)
|
|
78
97
|
if not plugin_dir:
|
|
79
98
|
return
|
|
@@ -145,7 +164,7 @@ async def pre_load(app=None):
|
|
|
145
164
|
print("Error in pre_load: " + str(e))
|
|
146
165
|
|
|
147
166
|
async def load(app=None):
|
|
148
|
-
"""Load all enabled plugins.
|
|
167
|
+
"""Load all enabled plugins with l8n translation support.
|
|
149
168
|
|
|
150
169
|
Args:
|
|
151
170
|
app (FastAPI, optional): The FastAPI application instance
|
|
@@ -197,6 +216,11 @@ async def load(app=None):
|
|
|
197
216
|
continue
|
|
198
217
|
|
|
199
218
|
# Import plugin module
|
|
219
|
+
print(termcolor.colored(
|
|
220
|
+
f"Tryin to import plugin: {plugin_name} ({category})",
|
|
221
|
+
'green'
|
|
222
|
+
))
|
|
223
|
+
#
|
|
200
224
|
try:
|
|
201
225
|
module = importlib.import_module(plugin_path)
|
|
202
226
|
except ImportError:
|
|
@@ -234,6 +258,11 @@ async def load(app=None):
|
|
|
234
258
|
router_path = os.path.join(plugin_dir, 'router.py')
|
|
235
259
|
|
|
236
260
|
if os.path.exists(router_path):
|
|
261
|
+
print(termcolor.colored(
|
|
262
|
+
f"Trying to include router for plugin: {plugin_name} path {plugin_path}",
|
|
263
|
+
'yellow'
|
|
264
|
+
))
|
|
265
|
+
|
|
237
266
|
router_module = importlib.import_module(f"{plugin_path}.router")
|
|
238
267
|
app.include_router(router_module.router)
|
|
239
268
|
print(termcolor.colored(
|
|
@@ -247,7 +276,8 @@ async def load(app=None):
|
|
|
247
276
|
trace = traceback.format_exc()
|
|
248
277
|
print(termcolor.colored(
|
|
249
278
|
f"Failed to load router for plugin: {plugin_name}\n{str(e)}\n{trace}",'red'))
|
|
250
|
-
|
|
279
|
+
|
|
280
|
+
# Mount static files with translation support
|
|
251
281
|
mount_static_files(app, plugin_name, category)
|
|
252
282
|
|
|
253
283
|
except Exception as e:
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import importlib
|
|
4
|
+
import termcolor
|
|
5
|
+
import traceback
|
|
6
|
+
from fastapi import FastAPI
|
|
7
|
+
from fastapi.staticfiles import StaticFiles
|
|
8
|
+
from starlette.middleware.base import BaseHTTPMiddleware
|
|
9
|
+
from .paths import get_plugin_path, get_plugin_import_path
|
|
10
|
+
from .manifest import list_enabled, load_plugin_manifest
|
|
11
|
+
from .installation import check_plugin_dependencies
|
|
12
|
+
from .l8n_static_handler import mount_translated_static_files
|
|
13
|
+
from mindroot.lib.utils.debug import debug_box
|
|
14
|
+
|
|
15
|
+
app_instance = None
|
|
16
|
+
|
|
17
|
+
def load_middleware(app, plugin_name, plugin_path, category):
|
|
18
|
+
"""Load plugin middleware if it exists.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
app (FastAPI): The FastAPI application instance
|
|
22
|
+
plugin_name (str): Name of the plugin
|
|
23
|
+
plugin_path (str): Import path of the plugin
|
|
24
|
+
"""
|
|
25
|
+
try:
|
|
26
|
+
plugin_dir = plugin_path # get_plugin_path(plugin_name)
|
|
27
|
+
if not plugin_dir:
|
|
28
|
+
print("No plugin_dir")
|
|
29
|
+
return
|
|
30
|
+
|
|
31
|
+
dir_name = os.path.basename(plugin_dir)
|
|
32
|
+
|
|
33
|
+
if category != 'core':
|
|
34
|
+
middleware_path = os.path.join(plugin_dir, 'src', dir_name, 'middleware.py')
|
|
35
|
+
else:
|
|
36
|
+
middleware_path = os.path.join(plugin_dir, 'middleware.py')
|
|
37
|
+
|
|
38
|
+
if os.path.exists(middleware_path):
|
|
39
|
+
|
|
40
|
+
plugin_import_path = get_plugin_import_path(plugin_name)
|
|
41
|
+
if not plugin_import_path:
|
|
42
|
+
failed_plugins.append(
|
|
43
|
+
(plugin_name, f"Failed to locate plugin: {plugin_name}")
|
|
44
|
+
)
|
|
45
|
+
print(f"Could not load middleware for plugin, failed to locate import path {plugin_name}")
|
|
46
|
+
return
|
|
47
|
+
|
|
48
|
+
module = None
|
|
49
|
+
# Import plugin module
|
|
50
|
+
try:
|
|
51
|
+
module = importlib.import_module(plugin_import_path)
|
|
52
|
+
except ImportError:
|
|
53
|
+
module = importlib.import_module(f"{plugin_import_path}.mod")
|
|
54
|
+
|
|
55
|
+
print(termcolor.colored(
|
|
56
|
+
f"Loaded plugin: {plugin_name} ({category})",
|
|
57
|
+
'green'
|
|
58
|
+
))
|
|
59
|
+
if hasattr(module, 'middleware'):
|
|
60
|
+
app.add_middleware(BaseHTTPMiddleware, dispatch=module.middleware)
|
|
61
|
+
print(f"Added middleware for plugin: {plugin_name}")
|
|
62
|
+
else:
|
|
63
|
+
print(f"Did not find middleware for {plugin_name} in {middleware_path}")
|
|
64
|
+
except ImportError as e:
|
|
65
|
+
trace = traceback.format_exc()
|
|
66
|
+
|
|
67
|
+
print(f"Could not import middleware for plugin {plugin_name} error was {e}\n\n{trace}")
|
|
68
|
+
print(f"No middleware loaded for plugin: {plugin_name}")
|
|
69
|
+
|
|
70
|
+
def mount_static_files(app, plugin_name, category):
|
|
71
|
+
"""Mount plugin static files with translation support if available.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
app (FastAPI): The FastAPI application instance
|
|
75
|
+
plugin_name (str): Name of the plugin
|
|
76
|
+
category (str): Plugin category ('core' or 'installed')
|
|
77
|
+
"""
|
|
78
|
+
try:
|
|
79
|
+
# Try to use translated static files first
|
|
80
|
+
mount_translated_static_files(app, plugin_name, category)
|
|
81
|
+
return
|
|
82
|
+
except Exception as e:
|
|
83
|
+
print(f"Could not mount translated static files for {plugin_name}: {e}")
|
|
84
|
+
print("Falling back to regular static file mounting")
|
|
85
|
+
|
|
86
|
+
# Fallback to regular static file mounting
|
|
87
|
+
plugin_dir = get_plugin_path(plugin_name)
|
|
88
|
+
if not plugin_dir:
|
|
89
|
+
return
|
|
90
|
+
|
|
91
|
+
dir_name = os.path.basename(plugin_dir)
|
|
92
|
+
|
|
93
|
+
if category != 'core':
|
|
94
|
+
static_path = os.path.join(plugin_dir, 'src', dir_name, 'static')
|
|
95
|
+
if not os.path.exists(static_path):
|
|
96
|
+
static_path = os.path.join(plugin_dir, 'static')
|
|
97
|
+
else:
|
|
98
|
+
static_path = os.path.join(plugin_dir, 'static')
|
|
99
|
+
|
|
100
|
+
if os.path.exists(static_path):
|
|
101
|
+
app.mount(
|
|
102
|
+
f"/{dir_name}/static",
|
|
103
|
+
StaticFiles(directory=static_path),
|
|
104
|
+
name=f"/{dir_name}/static"
|
|
105
|
+
)
|
|
106
|
+
print(termcolor.colored(
|
|
107
|
+
f"Mounted static files for plugin: {plugin_name} at {static_path}",
|
|
108
|
+
'green'
|
|
109
|
+
))
|
|
110
|
+
else:
|
|
111
|
+
print(termcolor.colored(
|
|
112
|
+
f"No static files found for plugin: {plugin_name}. Searched in {static_path}",
|
|
113
|
+
'yellow'
|
|
114
|
+
))
|
|
115
|
+
|
|
116
|
+
# pre_startup (e.g. middleware)
|
|
117
|
+
async def pre_load(app=None):
|
|
118
|
+
debug_box("Top of pre_load")
|
|
119
|
+
enabled_plugins = list_enabled()
|
|
120
|
+
global app_instance
|
|
121
|
+
|
|
122
|
+
# Setup app instance
|
|
123
|
+
if app is not None:
|
|
124
|
+
app_instance = app
|
|
125
|
+
elif app_instance is not None:
|
|
126
|
+
app = app_instance
|
|
127
|
+
else:
|
|
128
|
+
raise Exception("No FastAPI app instance provided or found")
|
|
129
|
+
|
|
130
|
+
# Add project root to Python path
|
|
131
|
+
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
132
|
+
project_root = os.path.dirname(os.path.dirname(current_dir))
|
|
133
|
+
if project_root not in sys.path:
|
|
134
|
+
sys.path.insert(0, project_root)
|
|
135
|
+
|
|
136
|
+
failed_plugins = []
|
|
137
|
+
|
|
138
|
+
enabled_plugins = [plugin for plugin in enabled_plugins if plugin[0] != 'startup']
|
|
139
|
+
print("inside of pre_load")
|
|
140
|
+
for plugin_name, category in enabled_plugins:
|
|
141
|
+
try:
|
|
142
|
+
print(f"Trying to get import path for {plugin_name}")
|
|
143
|
+
# Get plugin import path
|
|
144
|
+
plugin_path = get_plugin_path(plugin_name)
|
|
145
|
+
if not plugin_path:
|
|
146
|
+
failed_plugins.append(
|
|
147
|
+
(plugin_name, f"Failed to locate plugin: {plugin_name}")
|
|
148
|
+
)
|
|
149
|
+
print("Could not get import path")
|
|
150
|
+
continue
|
|
151
|
+
|
|
152
|
+
print(f"Trying to load middleware (if any) for {plugin_name}")
|
|
153
|
+
load_middleware(app, plugin_name, plugin_path, category)
|
|
154
|
+
except Exception as e:
|
|
155
|
+
print("Error in pre_load: " + str(e))
|
|
156
|
+
|
|
157
|
+
async def load(app=None):
|
|
158
|
+
"""Load all enabled plugins with l8n translation support.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
app (FastAPI, optional): The FastAPI application instance
|
|
162
|
+
|
|
163
|
+
Raises:
|
|
164
|
+
Exception: If no FastAPI instance is provided or found
|
|
165
|
+
"""
|
|
166
|
+
global app_instance
|
|
167
|
+
|
|
168
|
+
# Setup app instance
|
|
169
|
+
if app is not None:
|
|
170
|
+
app_instance = app
|
|
171
|
+
elif app_instance is not None:
|
|
172
|
+
app = app_instance
|
|
173
|
+
else:
|
|
174
|
+
raise Exception("No FastAPI app instance provided or found")
|
|
175
|
+
|
|
176
|
+
# Add project root to Python path
|
|
177
|
+
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
178
|
+
project_root = os.path.dirname(os.path.dirname(current_dir))
|
|
179
|
+
if project_root not in sys.path:
|
|
180
|
+
sys.path.insert(0, project_root)
|
|
181
|
+
|
|
182
|
+
# Load enabled plugins
|
|
183
|
+
enabled_plugins = list_enabled()
|
|
184
|
+
failed_plugins = []
|
|
185
|
+
|
|
186
|
+
enabled_plugins = [plugin for plugin in enabled_plugins if plugin[0] != 'startup']
|
|
187
|
+
enabled_plugins.append(('startup', 'core'))
|
|
188
|
+
|
|
189
|
+
print("Enabled plugins:")
|
|
190
|
+
print(enabled_plugins)
|
|
191
|
+
|
|
192
|
+
for plugin_name, category in enabled_plugins:
|
|
193
|
+
try:
|
|
194
|
+
# Get plugin import path
|
|
195
|
+
plugin_path = get_plugin_import_path(plugin_name)
|
|
196
|
+
if not plugin_path:
|
|
197
|
+
failed_plugins.append(
|
|
198
|
+
(plugin_name, f"Failed to locate plugin: {plugin_name}")
|
|
199
|
+
)
|
|
200
|
+
continue
|
|
201
|
+
|
|
202
|
+
# Check dependencies for non-core plugins
|
|
203
|
+
if category != 'core' and not check_plugin_dependencies(plugin_path):
|
|
204
|
+
failed_plugins.append(
|
|
205
|
+
(plugin_name, f"Dependencies not met for plugin {plugin_name}")
|
|
206
|
+
)
|
|
207
|
+
continue
|
|
208
|
+
|
|
209
|
+
# Import plugin module
|
|
210
|
+
try:
|
|
211
|
+
print(plugin_name, "Trying to import plugin module: " + plugin_path)
|
|
212
|
+
module = importlib.import_module(plugin_path)
|
|
213
|
+
except ImportError:
|
|
214
|
+
module = importlib.import_module(f"{plugin_path}.mod")
|
|
215
|
+
|
|
216
|
+
print(termcolor.colored(
|
|
217
|
+
f"Loaded plugin: {plugin_name} ({category})",
|
|
218
|
+
'green'
|
|
219
|
+
))
|
|
220
|
+
|
|
221
|
+
# Call plugin initialization
|
|
222
|
+
if hasattr(module, 'on_load'):
|
|
223
|
+
print(termcolor.colored(
|
|
224
|
+
f"Calling on_load() for plugin: {plugin_name}",
|
|
225
|
+
'yellow', 'on_green'
|
|
226
|
+
))
|
|
227
|
+
await module.on_load(app)
|
|
228
|
+
|
|
229
|
+
# Load router if exists
|
|
230
|
+
try:
|
|
231
|
+
# we need to see if the router.py actually exists
|
|
232
|
+
# because if not this isn't an error, it just means there is no router
|
|
233
|
+
# but if there is and we get an importerror, then we need to report that
|
|
234
|
+
# as an error
|
|
235
|
+
# so to detect if the file exists we need to import os
|
|
236
|
+
plugin_dir = get_plugin_path(plugin_name)
|
|
237
|
+
if not plugin_dir:
|
|
238
|
+
return
|
|
239
|
+
|
|
240
|
+
dir_name = os.path.basename(plugin_dir)
|
|
241
|
+
|
|
242
|
+
if category != 'core':
|
|
243
|
+
router_path = os.path.join(plugin_dir, 'src', dir_name, 'router.py')
|
|
244
|
+
else:
|
|
245
|
+
router_path = os.path.join(plugin_dir, 'router.py')
|
|
246
|
+
|
|
247
|
+
if os.path.exists(router_path):
|
|
248
|
+
print(termcolor.colored(
|
|
249
|
+
f">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Trying to load router for plugin: {plugin_name}",
|
|
250
|
+
'green'
|
|
251
|
+
))
|
|
252
|
+
|
|
253
|
+
print("Trying to load router for plugin: " + plugin_name)
|
|
254
|
+
router_module = importlib.import_module(f"{plugin_path}.router")
|
|
255
|
+
app.include_router(router_module.router)
|
|
256
|
+
print(termcolor.colored(
|
|
257
|
+
f"Included router for plugin: {plugin_name}",
|
|
258
|
+
'yellow'
|
|
259
|
+
))
|
|
260
|
+
else:
|
|
261
|
+
print(f"No router found for plugin: {plugin_name} at path {plugin_path}/router.py")
|
|
262
|
+
|
|
263
|
+
except ImportError as e:
|
|
264
|
+
trace = traceback.format_exc()
|
|
265
|
+
print(termcolor.colored(
|
|
266
|
+
f"Failed to load router for plugin: {plugin_name}\n{str(e)}\n{trace}",'red'))
|
|
267
|
+
|
|
268
|
+
# Mount static files with translation support
|
|
269
|
+
mount_static_files(app, plugin_name, category)
|
|
270
|
+
|
|
271
|
+
except Exception as e:
|
|
272
|
+
trace = traceback.format_exc()
|
|
273
|
+
failed_plugins.append(
|
|
274
|
+
(plugin_name, f"Failed to load plugin: {str(e)}\n{trace}")
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
# Report failed plugins
|
|
278
|
+
if failed_plugins:
|
|
279
|
+
print(termcolor.colored("Failed to load the following plugins:", 'red'))
|
|
280
|
+
for plugin_name, reason in failed_plugins:
|
|
281
|
+
print(f"{plugin_name}: {reason}")
|