mindroot 9.3.0__py3-none-any.whl → 9.6.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.
Files changed (183) hide show
  1. mindroot/coreplugins/admin/__init__.py +3 -1
  2. mindroot/coreplugins/admin/agent_router.py +250 -7
  3. mindroot/coreplugins/admin/asset_manager.py +164 -0
  4. mindroot/coreplugins/admin/command_router.py +236 -1
  5. mindroot/coreplugins/admin/mcp_catalog_routes.py +156 -0
  6. mindroot/coreplugins/admin/mcp_publish_routes.py +450 -0
  7. mindroot/coreplugins/admin/mcp_registry_routes.py +495 -0
  8. mindroot/coreplugins/admin/mcp_routes.py +216 -0
  9. mindroot/coreplugins/admin/mod.py +62 -0
  10. mindroot/coreplugins/admin/oauth_callback_router.py +84 -0
  11. mindroot/coreplugins/admin/persona_handler.py +15 -6
  12. mindroot/coreplugins/admin/persona_router.py +158 -2
  13. mindroot/coreplugins/admin/plugin_manager.py +105 -9
  14. mindroot/coreplugins/admin/plugin_router_fixed.py +23 -0
  15. mindroot/coreplugins/admin/plugin_router_new_not_working.py +145 -0
  16. mindroot/coreplugins/admin/plugin_routes.py +114 -0
  17. mindroot/coreplugins/admin/registry_settings_routes.py +140 -0
  18. mindroot/coreplugins/admin/router.py +116 -15
  19. mindroot/coreplugins/admin/service_models.py +1 -1
  20. mindroot/coreplugins/admin/settings_router.py +1 -0
  21. mindroot/coreplugins/admin/static/css/admin-custom.css +357 -2
  22. mindroot/coreplugins/admin/static/css/dark.css +1 -0
  23. mindroot/coreplugins/admin/static/css/default.css +4 -0
  24. mindroot/coreplugins/admin/static/js/about-info.js +367 -0
  25. mindroot/coreplugins/admin/static/js/agent-form.js +83 -3
  26. mindroot/coreplugins/admin/static/js/api-key-script.js +307 -0
  27. mindroot/coreplugins/admin/static/js/mcp-manager.js +348 -0
  28. mindroot/coreplugins/admin/static/js/mcp-publisher.js +780 -0
  29. mindroot/coreplugins/admin/static/js/persona-editor.js +34 -5
  30. mindroot/coreplugins/admin/static/js/plugin-toggle.js +1 -1
  31. mindroot/coreplugins/admin/static/js/recommended-plugin-install.js +63 -0
  32. mindroot/coreplugins/admin/static/js/registry-auth-section.js +132 -0
  33. mindroot/coreplugins/admin/static/js/registry-manager-base.js +613 -0
  34. mindroot/coreplugins/admin/static/js/registry-manager-publish-old-delete.js +166 -0
  35. mindroot/coreplugins/admin/static/js/registry-manager.js +351 -0
  36. mindroot/coreplugins/admin/static/js/registry-publish-section.js +377 -0
  37. mindroot/coreplugins/admin/static/js/registry-search-section.js +400 -0
  38. mindroot/coreplugins/admin/static/js/registry-search-section.js.bak +3 -0
  39. mindroot/coreplugins/admin/static/js/registry-settings.js +69 -0
  40. mindroot/coreplugins/admin/static/js/registry-shared-services.js +903 -0
  41. mindroot/coreplugins/admin/static/js/registry-simple-sections.js +85 -0
  42. mindroot/coreplugins/admin/static/js/secure-widget-manager.js +438 -0
  43. mindroot/coreplugins/admin/static/logo.png +0 -0
  44. mindroot/coreplugins/admin/templates/admin.jinja2 +275 -110
  45. mindroot/coreplugins/agent/Assistant/agent.json +27 -11
  46. mindroot/coreplugins/agent/agent.py +2 -2
  47. mindroot/coreplugins/agent/command_parser.py +25 -10
  48. mindroot/coreplugins/agent/templates/system.jinja2 +0 -12
  49. mindroot/coreplugins/chat/__init__.py +4 -1
  50. mindroot/coreplugins/chat/router.py +132 -20
  51. mindroot/coreplugins/chat/router_dedup_patch.py +20 -0
  52. mindroot/coreplugins/chat/services.py +31 -1
  53. mindroot/coreplugins/chat/static/css/action-fix.css +32 -0
  54. mindroot/coreplugins/chat/static/css/admin-custom.css +5 -3
  55. mindroot/coreplugins/chat/static/css/dark.css +24 -3
  56. mindroot/coreplugins/chat/static/css/default.css +24 -3
  57. mindroot/coreplugins/chat/static/css/main.css +1 -0
  58. mindroot/coreplugins/chat/static/js/action.js +137 -60
  59. mindroot/coreplugins/chat/static/js/chat-history.js +3 -0
  60. mindroot/coreplugins/chat/static/js/chat.js +59 -16
  61. mindroot/coreplugins/chat/static/js/chat.js.diff +221 -0
  62. mindroot/coreplugins/chat/static/js/chatform.js +2 -2
  63. mindroot/coreplugins/chat/static/site.webmanifest +1 -1
  64. mindroot/coreplugins/chat/templates/chat.jinja2 +3 -3
  65. mindroot/coreplugins/chat/widget_manager.py +139 -0
  66. mindroot/coreplugins/chat/widget_routes.py +287 -0
  67. mindroot/coreplugins/check_list/inject/admin.jinja2 +1 -1
  68. mindroot/coreplugins/email/__init__.py +2 -0
  69. mindroot/coreplugins/email/email_provider.py +2 -2
  70. mindroot/coreplugins/email/mod.py +100 -0
  71. mindroot/coreplugins/email/services.py +5 -3
  72. mindroot/coreplugins/email/smtp_handler.py +9 -3
  73. mindroot/coreplugins/email/test_email_service.py +75 -0
  74. mindroot/coreplugins/env_manager/mod.py +61 -25
  75. mindroot/coreplugins/home/router.py +37 -2
  76. mindroot/coreplugins/home/static/imgs/logo.png +0 -0
  77. mindroot/coreplugins/home/static/imgs/logo.png.bak +0 -0
  78. mindroot/coreplugins/home/static/imgs/logo_teal.png +0 -0
  79. mindroot/coreplugins/home/static/imgs/logo_teal2.png +0 -0
  80. mindroot/coreplugins/home/static/imgs/logo_teal_detailed.png +0 -0
  81. mindroot/coreplugins/home/static/imgs/logo_teal_python.png +0 -0
  82. mindroot/coreplugins/home/templates/home.jinja2 +15 -6
  83. mindroot/coreplugins/index/indices/default/index.json +39 -6
  84. mindroot/coreplugins/jwt_auth/middleware.py +47 -2
  85. mindroot/coreplugins/jwt_auth/mod.py +40 -17
  86. mindroot/coreplugins/l8n/__init__.py +6 -0
  87. mindroot/coreplugins/l8n/debug_loader.py +85 -0
  88. mindroot/coreplugins/l8n/debug_middleware.py +74 -0
  89. mindroot/coreplugins/l8n/l8n_constants.py +19 -0
  90. mindroot/coreplugins/l8n/language_detection.py +183 -0
  91. mindroot/coreplugins/l8n/middleware.py +151 -0
  92. mindroot/coreplugins/l8n/mod.py +277 -0
  93. mindroot/coreplugins/l8n/monkey_patch_to_delete.py +186 -0
  94. mindroot/coreplugins/l8n/test_enhanced.py +298 -0
  95. mindroot/coreplugins/l8n/test_l8n.py +95 -0
  96. mindroot/coreplugins/l8n/test_l8n_standalone.py +251 -0
  97. mindroot/coreplugins/l8n/test_middleware.py +272 -0
  98. mindroot/coreplugins/l8n/utils.py +232 -0
  99. mindroot/coreplugins/mcp_/__init__.py +14 -0
  100. mindroot/coreplugins/mcp_/catalog_commands.py +328 -0
  101. mindroot/coreplugins/mcp_/catalog_manager.py +263 -0
  102. mindroot/coreplugins/mcp_/dynamic_commands.py +154 -0
  103. mindroot/coreplugins/mcp_/mcp_manager.py +1031 -0
  104. mindroot/coreplugins/mcp_/mod.py +367 -0
  105. mindroot/coreplugins/mcp_/oauth_storage.py +144 -0
  106. mindroot/coreplugins/mcp_/server_installer.py +79 -0
  107. mindroot/coreplugins/mcp_/setup.py +26 -0
  108. mindroot/coreplugins/mcp_/test_dynamic_commands.py +134 -0
  109. mindroot/coreplugins/mcp_/testmcpclient.py +92 -0
  110. mindroot/coreplugins/persona/mod.py +12 -7
  111. mindroot/coreplugins/signup/templates/signup.jinja2 +1 -1
  112. mindroot/coreplugins/subscriptions/__init__.py +1 -0
  113. mindroot/coreplugins/subscriptions/mod.py +14 -3
  114. mindroot/coreplugins/subscriptions/router.py +3 -0
  115. mindroot/coreplugins/user_service/__init__.py +1 -2
  116. mindroot/coreplugins/user_service/admin_init.py +1 -0
  117. mindroot/coreplugins/user_service/email_service.py +72 -17
  118. mindroot/coreplugins/user_service/mod.py +10 -2
  119. mindroot/coreplugins/user_service/router.py +2 -0
  120. mindroot/lib/auth/api_key.py +28 -0
  121. mindroot/lib/cli/plugins.py +94 -0
  122. mindroot/lib/plugins/default_plugin_manifest.json +20 -0
  123. mindroot/lib/plugins/installation.py +5 -5
  124. mindroot/lib/plugins/l8n_static_handler.py +225 -0
  125. mindroot/lib/plugins/loader.py +33 -3
  126. mindroot/lib/plugins/loader_with_l8n.py +281 -0
  127. mindroot/lib/plugins/manifest.py +236 -24
  128. mindroot/lib/providers/commands.py +3 -1
  129. mindroot/lib/route_decorators.py +5 -5
  130. mindroot/lib/templates.py +183 -11
  131. mindroot/lib/utils/merge_arrays.py +1 -1
  132. mindroot/migrate.py +39 -20
  133. mindroot/registry/data_access.py +1 -1
  134. mindroot/server.py +42 -13
  135. mindroot/server_missing_normal_args.py +197 -0
  136. mindroot/server_prev.py +173 -0
  137. {mindroot-9.3.0.dist-info → mindroot-9.6.0.dist-info}/METADATA +7 -2
  138. {mindroot-9.3.0.dist-info → mindroot-9.6.0.dist-info}/RECORD +143 -113
  139. mindroot/coreplugins/admin/plugin_manager_backup.py +0 -615
  140. mindroot/coreplugins/admin/static/favicon/about.txt +0 -6
  141. mindroot/coreplugins/admin/static/favicon/android-chrome-512x512.png +0 -0
  142. mindroot/coreplugins/admin/static/favicon/apple-touch-icon.png +0 -0
  143. mindroot/coreplugins/admin/static/favicon/favicon-16x16.png +0 -0
  144. mindroot/coreplugins/admin/static/favicon/favicon-32x32.png +0 -0
  145. mindroot/coreplugins/admin/static/favicon/favicon.ico +0 -0
  146. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/about.txt +0 -6
  147. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/android-chrome-192x192.png +0 -0
  148. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/android-chrome-512x512.png +0 -0
  149. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/apple-touch-icon.png +0 -0
  150. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/favicon-16x16.png +0 -0
  151. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/favicon-32x32.png +0 -0
  152. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/favicon.ico +0 -0
  153. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/site.webmanifest +0 -1
  154. mindroot/coreplugins/admin/static/favicon/logo.png +0 -0
  155. mindroot/coreplugins/admin/static/favicon/site.webmanifest +0 -1
  156. mindroot/coreplugins/admin/static/js/backup/agent-editor.js +0 -186
  157. mindroot/coreplugins/admin/static/js/backup/agent-form.js +0 -1133
  158. mindroot/coreplugins/admin/static/js/backup/agent-list.js +0 -94
  159. mindroot/coreplugins/chat/static/favicon/about.txt +0 -6
  160. mindroot/coreplugins/chat/static/favicon/android-chrome-192x192.png +0 -0
  161. mindroot/coreplugins/chat/static/favicon/android-chrome-512x512.png +0 -0
  162. mindroot/coreplugins/chat/static/favicon/apple-touch-icon.png +0 -0
  163. mindroot/coreplugins/chat/static/favicon/favicon-16x16.png +0 -0
  164. mindroot/coreplugins/chat/static/favicon/favicon-32x32.png +0 -0
  165. mindroot/coreplugins/chat/static/favicon/favicon.ico +0 -0
  166. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/about.txt +0 -6
  167. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/android-chrome-192x192.png +0 -0
  168. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/android-chrome-512x512.png +0 -0
  169. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/apple-touch-icon.png +0 -0
  170. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/favicon-16x16.png +0 -0
  171. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/favicon-32x32.png +0 -0
  172. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/favicon.ico +0 -0
  173. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/site.webmanifest +0 -1
  174. mindroot/coreplugins/chat/static/favicon/logo.png +0 -0
  175. mindroot/coreplugins/chat/static/favicon/site.webmanifest +0 -1
  176. mindroot/coreplugins/index/default.json +0 -76
  177. mindroot/coreplugins/user_service/file_trigger_service.py +0 -12
  178. mindroot/coreplugins/user_service/hooks.py +0 -23
  179. /mindroot/coreplugins/{admin/static/favicon/android-chrome-192x192.png → home/static/imgs/backuplogo.png} +0 -0
  180. {mindroot-9.3.0.dist-info → mindroot-9.6.0.dist-info}/WHEEL +0 -0
  181. {mindroot-9.3.0.dist-info → mindroot-9.6.0.dist-info}/entry_points.txt +0 -0
  182. {mindroot-9.3.0.dist-info → mindroot-9.6.0.dist-info}/licenses/LICENSE +0 -0
  183. {mindroot-9.3.0.dist-info → mindroot-9.6.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', plugin.get('github_url', plugin.get('source')))
286
- print(f"Checking plugin Index plugin {remote_source} against recommended {plugin_source}")
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 = github_url.split('github.com/')[1]
290
- print(f"Extracted GitHub path for {plugin_name}: {github_path}")
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
@@ -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 they exist.
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
- # Mount static files
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}")