mindroot 9.2.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.py +1 -1
- 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/handlers/plugin_ops.py +1 -1
- mindroot/coreplugins/index/indices/default/index.json +6 -6
- mindroot/coreplugins/jwt_auth/middleware.py +47 -1
- 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/password_reset_service.py +180 -27
- mindroot/coreplugins/user_service/router.py +84 -22
- 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 +238 -17
- 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 +49 -0
- mindroot/registry/data_access.py +1 -1
- mindroot/server.py +47 -13
- mindroot/server_missing_normal_args.py +197 -0
- mindroot/server_prev.py +173 -0
- {mindroot-9.2.0.dist-info → mindroot-9.5.0.dist-info}/METADATA +7 -2
- {mindroot-9.2.0.dist-info → mindroot-9.5.0.dist-info}/RECORD +147 -114
- 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 -72
- 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.2.0.dist-info → mindroot-9.5.0.dist-info}/WHEEL +0 -0
- {mindroot-9.2.0.dist-info → mindroot-9.5.0.dist-info}/entry_points.txt +0 -0
- {mindroot-9.2.0.dist-info → mindroot-9.5.0.dist-info}/licenses/LICENSE +0 -0
- {mindroot-9.2.0.dist-info → mindroot-9.5.0.dist-info}/top_level.txt +0 -0
mindroot/lib/plugins/manifest.py
CHANGED
|
@@ -1,9 +1,215 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import os
|
|
3
|
+
import shutil
|
|
4
|
+
import tempfile
|
|
5
|
+
import logging
|
|
3
6
|
from datetime import datetime
|
|
7
|
+
from pathlib import Path
|
|
4
8
|
|
|
5
9
|
# Central definition of manifest file location
|
|
6
|
-
MANIFEST_FILE = 'plugin_manifest.json'
|
|
10
|
+
MANIFEST_FILE = 'data/plugin_manifest.json'
|
|
11
|
+
|
|
12
|
+
# Setup logging
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
def _get_absolute_paths():
|
|
16
|
+
"""Get absolute paths for all manifest-related files.
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
tuple: (manifest_abs_path, root_manifest_abs_path, data_dir_abs_path)
|
|
20
|
+
"""
|
|
21
|
+
cwd = os.getcwd()
|
|
22
|
+
manifest_abs_path = os.path.abspath(os.path.join(cwd, MANIFEST_FILE))
|
|
23
|
+
root_manifest_abs_path = os.path.abspath(os.path.join(cwd, 'plugin_manifest.json'))
|
|
24
|
+
data_dir_abs_path = os.path.abspath(os.path.join(cwd, 'data'))
|
|
25
|
+
|
|
26
|
+
return manifest_abs_path, root_manifest_abs_path, data_dir_abs_path
|
|
27
|
+
|
|
28
|
+
def _backup_manifest(manifest_path):
|
|
29
|
+
"""Create a backup of the existing manifest file.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
manifest_path (str): Absolute path to the manifest file
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
str: Path to backup file, or None if backup failed
|
|
36
|
+
"""
|
|
37
|
+
if not os.path.exists(manifest_path):
|
|
38
|
+
return None
|
|
39
|
+
|
|
40
|
+
try:
|
|
41
|
+
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
|
42
|
+
backup_path = f"{manifest_path}.backup_{timestamp}"
|
|
43
|
+
shutil.copy2(manifest_path, backup_path)
|
|
44
|
+
logger.info(f"Created manifest backup: {backup_path}")
|
|
45
|
+
return backup_path
|
|
46
|
+
except Exception as e:
|
|
47
|
+
logger.error(f"Failed to create manifest backup: {e}")
|
|
48
|
+
return None
|
|
49
|
+
|
|
50
|
+
def _atomic_write_manifest(manifest_path, manifest_data):
|
|
51
|
+
"""Atomically write manifest data to file.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
manifest_path (str): Absolute path to the manifest file
|
|
55
|
+
manifest_data (dict): Manifest data to write
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
bool: True if successful, False otherwise
|
|
59
|
+
"""
|
|
60
|
+
try:
|
|
61
|
+
# Ensure directory exists
|
|
62
|
+
os.makedirs(os.path.dirname(manifest_path), exist_ok=True)
|
|
63
|
+
|
|
64
|
+
# Write to temporary file first
|
|
65
|
+
with tempfile.NamedTemporaryFile(mode='w', suffix='.tmp',
|
|
66
|
+
dir=os.path.dirname(manifest_path),
|
|
67
|
+
delete=False) as tmp_file:
|
|
68
|
+
json.dump(manifest_data, tmp_file, indent=2)
|
|
69
|
+
tmp_path = tmp_file.name
|
|
70
|
+
|
|
71
|
+
# Atomic move to final location
|
|
72
|
+
shutil.move(tmp_path, manifest_path)
|
|
73
|
+
logger.debug(f"Atomically wrote manifest to: {manifest_path}")
|
|
74
|
+
return True
|
|
75
|
+
|
|
76
|
+
except Exception as e:
|
|
77
|
+
logger.error(f"Failed to atomically write manifest: {e}")
|
|
78
|
+
# Clean up temp file if it exists
|
|
79
|
+
try:
|
|
80
|
+
if 'tmp_path' in locals() and os.path.exists(tmp_path):
|
|
81
|
+
os.unlink(tmp_path)
|
|
82
|
+
except:
|
|
83
|
+
pass
|
|
84
|
+
return False
|
|
85
|
+
|
|
86
|
+
def _validate_manifest(manifest_path):
|
|
87
|
+
"""Validate that a manifest file exists and contains valid JSON.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
manifest_path (str): Absolute path to the manifest file
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
tuple: (is_valid, manifest_data_or_none)
|
|
94
|
+
"""
|
|
95
|
+
if not os.path.exists(manifest_path):
|
|
96
|
+
return False, None
|
|
97
|
+
|
|
98
|
+
try:
|
|
99
|
+
with open(manifest_path, 'r') as f:
|
|
100
|
+
manifest_data = json.load(f)
|
|
101
|
+
|
|
102
|
+
# Basic structure validation
|
|
103
|
+
if not isinstance(manifest_data, dict):
|
|
104
|
+
logger.warning(f"Manifest is not a dict: {manifest_path}")
|
|
105
|
+
return False, None
|
|
106
|
+
|
|
107
|
+
if 'plugins' not in manifest_data:
|
|
108
|
+
logger.warning(f"Manifest missing 'plugins' key: {manifest_path}")
|
|
109
|
+
return False, None
|
|
110
|
+
|
|
111
|
+
return True, manifest_data
|
|
112
|
+
|
|
113
|
+
except json.JSONDecodeError as e:
|
|
114
|
+
logger.warning(f"Manifest contains invalid JSON: {manifest_path} - {e}")
|
|
115
|
+
return False, None
|
|
116
|
+
except Exception as e:
|
|
117
|
+
logger.error(f"Error validating manifest: {manifest_path} - {e}")
|
|
118
|
+
return False, None
|
|
119
|
+
|
|
120
|
+
def _migrate_manifest_from_root():
|
|
121
|
+
"""Migrate manifest from root directory to data directory if needed.
|
|
122
|
+
|
|
123
|
+
This function consolidates the migration logic and uses absolute paths.
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
bool: True if migration was successful or not needed, False if failed
|
|
127
|
+
"""
|
|
128
|
+
manifest_abs_path, root_manifest_abs_path, data_dir_abs_path = _get_absolute_paths()
|
|
129
|
+
|
|
130
|
+
logger.debug(f"Checking for manifest migration:")
|
|
131
|
+
logger.debug(f" Target: {manifest_abs_path}")
|
|
132
|
+
logger.debug(f" Source: {root_manifest_abs_path}")
|
|
133
|
+
|
|
134
|
+
# If target already exists and is valid, no migration needed
|
|
135
|
+
is_valid, _ = _validate_manifest(manifest_abs_path)
|
|
136
|
+
if is_valid:
|
|
137
|
+
logger.debug(f"Valid manifest already exists at: {manifest_abs_path}")
|
|
138
|
+
return True
|
|
139
|
+
|
|
140
|
+
# If target exists but is invalid, back it up
|
|
141
|
+
if os.path.exists(manifest_abs_path):
|
|
142
|
+
logger.warning(f"Invalid manifest found at {manifest_abs_path}, backing up")
|
|
143
|
+
_backup_manifest(manifest_abs_path)
|
|
144
|
+
|
|
145
|
+
# Check if source manifest exists and is valid
|
|
146
|
+
is_valid, manifest_data = _validate_manifest(root_manifest_abs_path)
|
|
147
|
+
if is_valid:
|
|
148
|
+
logger.info(f"Migrating manifest from {root_manifest_abs_path} to {manifest_abs_path}")
|
|
149
|
+
|
|
150
|
+
# Ensure data directory exists
|
|
151
|
+
os.makedirs(data_dir_abs_path, exist_ok=True)
|
|
152
|
+
|
|
153
|
+
# Atomic write to new location
|
|
154
|
+
if _atomic_write_manifest(manifest_abs_path, manifest_data):
|
|
155
|
+
# Remove old file only after successful write
|
|
156
|
+
try:
|
|
157
|
+
os.unlink(root_manifest_abs_path)
|
|
158
|
+
logger.info(f"Successfully migrated manifest and removed old file")
|
|
159
|
+
return True
|
|
160
|
+
except Exception as e:
|
|
161
|
+
logger.warning(f"Manifest migrated but failed to remove old file: {e}")
|
|
162
|
+
return True
|
|
163
|
+
else:
|
|
164
|
+
logger.error(f"Failed to write migrated manifest")
|
|
165
|
+
return False
|
|
166
|
+
|
|
167
|
+
logger.debug(f"No valid manifest found to migrate from {root_manifest_abs_path}")
|
|
168
|
+
return True # Not an error - just no migration needed
|
|
169
|
+
|
|
170
|
+
def create_default_plugin_manifest():
|
|
171
|
+
"""Create a new default manifest file.
|
|
172
|
+
|
|
173
|
+
This function first attempts migration, then creates from default template if needed.
|
|
174
|
+
"""
|
|
175
|
+
manifest_abs_path, _, data_dir_abs_path = _get_absolute_paths()
|
|
176
|
+
|
|
177
|
+
logger.info(f"Creating default plugin manifest at: {manifest_abs_path}")
|
|
178
|
+
|
|
179
|
+
# First attempt migration from root directory
|
|
180
|
+
if _migrate_manifest_from_root():
|
|
181
|
+
# Check if migration was successful
|
|
182
|
+
is_valid, _ = _validate_manifest(manifest_abs_path)
|
|
183
|
+
if is_valid:
|
|
184
|
+
logger.info(f"Manifest successfully migrated from root directory")
|
|
185
|
+
return
|
|
186
|
+
|
|
187
|
+
# Migration didn't work, create from default template
|
|
188
|
+
logger.info(f"Creating manifest from default template")
|
|
189
|
+
|
|
190
|
+
# Backup existing file if it exists (even if invalid)
|
|
191
|
+
if os.path.exists(manifest_abs_path):
|
|
192
|
+
_backup_manifest(manifest_abs_path)
|
|
193
|
+
|
|
194
|
+
try:
|
|
195
|
+
# Read default template
|
|
196
|
+
default_manifest_path = os.path.join(os.path.dirname(__file__), 'default_plugin_manifest.json')
|
|
197
|
+
with open(default_manifest_path, 'r') as f:
|
|
198
|
+
default_manifest = json.load(f)
|
|
199
|
+
|
|
200
|
+
# Ensure data directory exists
|
|
201
|
+
os.makedirs(data_dir_abs_path, exist_ok=True)
|
|
202
|
+
|
|
203
|
+
# Atomic write
|
|
204
|
+
if _atomic_write_manifest(manifest_abs_path, default_manifest):
|
|
205
|
+
logger.info(f"Successfully created default manifest")
|
|
206
|
+
else:
|
|
207
|
+
logger.error(f"Failed to create default manifest")
|
|
208
|
+
raise Exception("Failed to write default manifest")
|
|
209
|
+
|
|
210
|
+
except Exception as e:
|
|
211
|
+
logger.error(f"Failed to create default manifest: {e}")
|
|
212
|
+
raise
|
|
7
213
|
|
|
8
214
|
def load_plugin_manifest():
|
|
9
215
|
"""Load the plugin manifest file.
|
|
@@ -11,12 +217,26 @@ def load_plugin_manifest():
|
|
|
11
217
|
Returns:
|
|
12
218
|
dict: The manifest data structure
|
|
13
219
|
"""
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
220
|
+
manifest_abs_path, _, _ = _get_absolute_paths()
|
|
221
|
+
|
|
222
|
+
# Validate existing manifest
|
|
223
|
+
is_valid, manifest_data = _validate_manifest(manifest_abs_path)
|
|
224
|
+
|
|
225
|
+
if is_valid:
|
|
226
|
+
logger.debug(f"Loaded valid manifest from: {manifest_abs_path}")
|
|
227
|
+
return manifest_data
|
|
228
|
+
|
|
229
|
+
# Manifest is missing or invalid, create default
|
|
230
|
+
logger.warning(f"Manifest missing or invalid at {manifest_abs_path}, creating default")
|
|
231
|
+
create_default_plugin_manifest()
|
|
232
|
+
|
|
233
|
+
# Load the newly created manifest
|
|
234
|
+
is_valid, manifest_data = _validate_manifest(manifest_abs_path)
|
|
235
|
+
if is_valid:
|
|
236
|
+
return manifest_data
|
|
237
|
+
else:
|
|
238
|
+
logger.error(f"Failed to create valid default manifest")
|
|
239
|
+
raise Exception("Could not load or create valid plugin manifest")
|
|
20
240
|
|
|
21
241
|
def save_plugin_manifest(manifest):
|
|
22
242
|
"""Save the plugin manifest file.
|
|
@@ -24,8 +244,17 @@ def save_plugin_manifest(manifest):
|
|
|
24
244
|
Args:
|
|
25
245
|
manifest (dict): The manifest data structure to save
|
|
26
246
|
"""
|
|
27
|
-
|
|
28
|
-
|
|
247
|
+
manifest_abs_path, _, _ = _get_absolute_paths()
|
|
248
|
+
|
|
249
|
+
# Backup existing manifest before saving
|
|
250
|
+
_backup_manifest(manifest_abs_path)
|
|
251
|
+
|
|
252
|
+
# Atomic write
|
|
253
|
+
if not _atomic_write_manifest(manifest_abs_path, manifest):
|
|
254
|
+
logger.error(f"Failed to save plugin manifest")
|
|
255
|
+
raise Exception("Failed to save plugin manifest")
|
|
256
|
+
|
|
257
|
+
logger.debug(f"Successfully saved manifest to: {manifest_abs_path}")
|
|
29
258
|
|
|
30
259
|
def update_plugin_manifest(plugin_name, source, source_path, remote_source=None, version="0.0.1", metadata=None):
|
|
31
260
|
"""Update or add a plugin entry in the manifest.
|
|
@@ -66,14 +295,6 @@ def update_plugin_manifest(plugin_name, source, source_path, remote_source=None,
|
|
|
66
295
|
|
|
67
296
|
save_plugin_manifest(manifest)
|
|
68
297
|
|
|
69
|
-
def create_default_plugin_manifest():
|
|
70
|
-
"""Create a new default manifest file."""
|
|
71
|
-
# read from default_plugin_manifest.json in same dir as this file
|
|
72
|
-
default_manifest_path = os.path.join(os.path.dirname(__file__), 'default_plugin_manifest.json')
|
|
73
|
-
with open(default_manifest_path, 'r') as f:
|
|
74
|
-
default_manifest = json.load(f)
|
|
75
|
-
save_plugin_manifest(default_manifest)
|
|
76
|
-
|
|
77
298
|
def toggle_plugin_state(plugin_name, enabled):
|
|
78
299
|
"""Toggle a plugin's enabled state.
|
|
79
300
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import inspect
|
|
2
2
|
import os
|
|
3
3
|
from . import ProviderManager
|
|
4
|
+
from mindroot.lib.utils.debug import debug_box
|
|
4
5
|
|
|
5
6
|
command_manager = ProviderManager()
|
|
6
7
|
|
|
@@ -14,7 +15,8 @@ def command(*, flags=[]):
|
|
|
14
15
|
raise ValueError("Cannot determine module of function")
|
|
15
16
|
|
|
16
17
|
module_name = os.path.basename(os.path.dirname(module.__file__))
|
|
17
|
-
|
|
18
|
+
if module_name == 'l8n':
|
|
19
|
+
debug_box("registering l8n command!" + name)
|
|
18
20
|
command_manager.register_function(name, module_name, func, signature, docstring, flags)
|
|
19
21
|
return func
|
|
20
22
|
return decorator
|
mindroot/lib/route_decorators.py
CHANGED
|
@@ -9,23 +9,23 @@ public_routes: Set[str] = set()
|
|
|
9
9
|
public_static: Set[str] = set()
|
|
10
10
|
|
|
11
11
|
def public_route():
|
|
12
|
-
|
|
13
|
-
print("public_route decorator called", public_routes)
|
|
12
|
+
"""Decorator to mark a route as public (no authentication required)"""
|
|
14
13
|
def decorator(func):
|
|
15
14
|
@wraps(func)
|
|
16
15
|
async def wrapper(*args, **kwargs):
|
|
17
|
-
|
|
16
|
+
# Mark the request as a public route for any middleware that needs to know
|
|
18
17
|
request: Request = next((arg for arg in args if isinstance(arg, Request)), None)
|
|
19
18
|
if request:
|
|
20
19
|
request.state.public_route = True
|
|
21
20
|
return await func(*args, **kwargs)
|
|
21
|
+
|
|
22
|
+
# Mark the function as a public route so the startup hook can find it
|
|
22
23
|
wrapper.__public_route__ = True
|
|
23
|
-
public_routes.add(func.__name__)
|
|
24
|
-
print("wrapper.__public_route__", wrapper.__public_route__)
|
|
25
24
|
return wrapper
|
|
26
25
|
return decorator
|
|
27
26
|
|
|
28
27
|
def add_public_static(path_start):
|
|
28
|
+
"""Add a path prefix to the public static routes"""
|
|
29
29
|
public_static.add(path_start)
|
|
30
30
|
|
|
31
31
|
# New role-based dependency functions
|
mindroot/lib/templates.py
CHANGED
|
@@ -4,12 +4,133 @@ from jinja2 import Environment, FileSystemLoader, ChoiceLoader
|
|
|
4
4
|
from .plugins import list_enabled, get_plugin_path
|
|
5
5
|
from .parent_templates import get_parent_templates_env
|
|
6
6
|
import traceback
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
# Import l8n translation functions
|
|
10
|
+
try:
|
|
11
|
+
from mindroot.coreplugins.l8n.utils import replace_placeholders, get_localized_file_path, extract_plugin_root
|
|
12
|
+
from mindroot.coreplugins.l8n.mod import *
|
|
13
|
+
from mindroot.coreplugins.l8n.middleware import get_request_language
|
|
14
|
+
from mindroot.coreplugins.l8n.language_detection import get_fallback_language
|
|
15
|
+
L8N_AVAILABLE = True
|
|
16
|
+
except ImportError as e:
|
|
17
|
+
trace = traceback.format_exc()
|
|
18
|
+
print(f"L8n not available: {e} \n{trace}")
|
|
19
|
+
L8N_AVAILABLE = False
|
|
20
|
+
sys.exit(1)
|
|
7
21
|
|
|
8
22
|
# TODO: get_parent_templates_env(plugins):
|
|
9
23
|
# jinja2 environment containing only 1 template per plugin file name,
|
|
10
24
|
# the first one that is found from plugins with that name,
|
|
11
25
|
# need to look at how jinja2 loaders work
|
|
12
26
|
|
|
27
|
+
def get_current_language():
|
|
28
|
+
"""Get the current language for translation."""
|
|
29
|
+
if not L8N_AVAILABLE:
|
|
30
|
+
return 'en'
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
# Try to get language from request context
|
|
34
|
+
lang = get_request_language()
|
|
35
|
+
return get_fallback_language(lang) if lang else 'en'
|
|
36
|
+
except Exception as e:
|
|
37
|
+
print(f"Error getting current language: {e}")
|
|
38
|
+
return 'en'
|
|
39
|
+
|
|
40
|
+
def apply_translations_to_content(content, template_path=None):
|
|
41
|
+
"""Apply l8n translations to template content.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
content (str): Template content with __TRANSLATE_key__ placeholders
|
|
45
|
+
template_path (str): Path to the template file for plugin context
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
str or None: Content with translations applied, or None if translations are incomplete
|
|
49
|
+
"""
|
|
50
|
+
if not L8N_AVAILABLE or not content:
|
|
51
|
+
return content
|
|
52
|
+
|
|
53
|
+
try:
|
|
54
|
+
current_language = get_current_language()
|
|
55
|
+
|
|
56
|
+
# If we have a template path, use it for plugin context
|
|
57
|
+
if template_path:
|
|
58
|
+
# Check if translation failed (missing translations)
|
|
59
|
+
translated = replace_placeholders(content, current_language, template_path)
|
|
60
|
+
if translated is None:
|
|
61
|
+
return None # Signal that translations are incomplete
|
|
62
|
+
return translated
|
|
63
|
+
else:
|
|
64
|
+
# Fallback: try to replace without plugin context
|
|
65
|
+
return replace_placeholders(content, current_language)
|
|
66
|
+
except Exception as e:
|
|
67
|
+
print(f"Error applying translations: {e}")
|
|
68
|
+
return content
|
|
69
|
+
|
|
70
|
+
def check_for_localized_template(template_path):
|
|
71
|
+
"""Check if a localized version of a template exists.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
template_path (str): Original template path
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
str: Path to localized template if it exists, None otherwise
|
|
78
|
+
"""
|
|
79
|
+
if not L8N_AVAILABLE:
|
|
80
|
+
return None
|
|
81
|
+
|
|
82
|
+
try:
|
|
83
|
+
localized_path = get_localized_file_path(template_path)
|
|
84
|
+
if localized_path.exists():
|
|
85
|
+
return str(localized_path)
|
|
86
|
+
except Exception as e:
|
|
87
|
+
print(f"Error checking for localized template: {e}")
|
|
88
|
+
|
|
89
|
+
return None
|
|
90
|
+
|
|
91
|
+
def load_template_with_translation(template_path):
|
|
92
|
+
"""Load a template and apply translations if available and complete.
|
|
93
|
+
|
|
94
|
+
If translations are missing for the current language, this function
|
|
95
|
+
will fall back to serving the original template to avoid showing
|
|
96
|
+
__TRANSLATE_key__ placeholders to users.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
template_path (str): Path to the template file
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
str: Template content with translations applied, or original content
|
|
103
|
+
if translations are incomplete for the current language
|
|
104
|
+
"""
|
|
105
|
+
# First check for localized version
|
|
106
|
+
localized_path = check_for_localized_template(template_path)
|
|
107
|
+
|
|
108
|
+
if localized_path:
|
|
109
|
+
# Load localized template and apply translations
|
|
110
|
+
try:
|
|
111
|
+
with open(localized_path, 'r', encoding='utf-8') as f:
|
|
112
|
+
content = f.read()
|
|
113
|
+
|
|
114
|
+
# Apply translations - if None is returned, translations are incomplete
|
|
115
|
+
translated_content = apply_translations_to_content(content, localized_path)
|
|
116
|
+
if translated_content is None:
|
|
117
|
+
# Fall back to original template
|
|
118
|
+
print(f"L8n: Falling back to original template due to missing translations: {template_path}")
|
|
119
|
+
with open(template_path, 'r', encoding='utf-8') as f:
|
|
120
|
+
return f.read()
|
|
121
|
+
return translated_content
|
|
122
|
+
except Exception as e:
|
|
123
|
+
print(f"Error loading localized template {localized_path}: {e}")
|
|
124
|
+
|
|
125
|
+
# Fallback to original template
|
|
126
|
+
try:
|
|
127
|
+
with open(template_path, 'r', encoding='utf-8') as f:
|
|
128
|
+
content = f.read()
|
|
129
|
+
return content # Don't apply translations to original templates
|
|
130
|
+
except Exception as e:
|
|
131
|
+
print(f"Error loading template {template_path}: {e}")
|
|
132
|
+
return ""
|
|
133
|
+
|
|
13
134
|
def setup_template_environment(plugins=None):
|
|
14
135
|
"""Set up Jinja2 environment with multiple template paths.
|
|
15
136
|
|
|
@@ -106,7 +227,6 @@ async def find_parent_template(page_name, plugins):
|
|
|
106
227
|
return rel_path
|
|
107
228
|
return alt_path
|
|
108
229
|
return None
|
|
109
|
-
|
|
110
230
|
async def find_plugin_template(page_name, plugins):
|
|
111
231
|
"""Find a template in a plugin's templates directory.
|
|
112
232
|
|
|
@@ -148,7 +268,7 @@ async def find_plugin_template(page_name, plugins):
|
|
|
148
268
|
return None, None
|
|
149
269
|
|
|
150
270
|
async def load_plugin_templates(page_name, plugins):
|
|
151
|
-
"""Load templates from plugins.
|
|
271
|
+
"""Load templates from plugins with translation support.
|
|
152
272
|
|
|
153
273
|
Args:
|
|
154
274
|
page_name (str): Name of the template page
|
|
@@ -180,9 +300,11 @@ async def load_plugin_templates(page_name, plugins):
|
|
|
180
300
|
|
|
181
301
|
for path in inject_paths:
|
|
182
302
|
if os.path.exists(path):
|
|
183
|
-
with
|
|
303
|
+
# Load template content with translation support
|
|
304
|
+
content = load_template_with_translation(path)
|
|
305
|
+
if content:
|
|
184
306
|
#print(f"Found inject template at: {path}")
|
|
185
|
-
templates.append({'type': 'inject', 'template': env.from_string(
|
|
307
|
+
templates.append({'type': 'inject', 'template': env.from_string(content)})
|
|
186
308
|
break
|
|
187
309
|
#else:
|
|
188
310
|
#
|
|
@@ -198,9 +320,11 @@ async def load_plugin_templates(page_name, plugins):
|
|
|
198
320
|
|
|
199
321
|
for path in override_paths:
|
|
200
322
|
if os.path.exists(path):
|
|
201
|
-
with
|
|
323
|
+
# Load template content with translation support
|
|
324
|
+
content = load_template_with_translation(path)
|
|
325
|
+
if content:
|
|
202
326
|
#print(f"Found override template at: {path}")
|
|
203
|
-
templates.append({'type': 'override', 'template': env.from_string(
|
|
327
|
+
templates.append({'type': 'override', 'template': env.from_string(content)})
|
|
204
328
|
break
|
|
205
329
|
|
|
206
330
|
except Exception as e:
|
|
@@ -232,7 +356,7 @@ async def collect_content(template, blocks, template_type, data):
|
|
|
232
356
|
return content
|
|
233
357
|
|
|
234
358
|
async def render_combined_template(page_name, plugins, context):
|
|
235
|
-
"""Render combined template with injections and overrides.
|
|
359
|
+
"""Render combined template with injections and overrides, including translation support.
|
|
236
360
|
|
|
237
361
|
Args:
|
|
238
362
|
page_name (str): Name of the template page
|
|
@@ -242,7 +366,37 @@ async def render_combined_template(page_name, plugins, context):
|
|
|
242
366
|
Returns:
|
|
243
367
|
str: Rendered HTML
|
|
244
368
|
"""
|
|
245
|
-
|
|
369
|
+
# Load parent template with translation support
|
|
370
|
+
parent_template = None
|
|
371
|
+
parent_template_path = None
|
|
372
|
+
|
|
373
|
+
# Find the parent template file path
|
|
374
|
+
# We need to search through the parent_env loaders to find the actual file
|
|
375
|
+
for loader in parent_env.loader.loaders:
|
|
376
|
+
for template_dir in loader.searchpath:
|
|
377
|
+
potential_path = os.path.join(template_dir, f"{page_name}.jinja2")
|
|
378
|
+
if os.path.exists(potential_path):
|
|
379
|
+
parent_template_path = potential_path
|
|
380
|
+
break
|
|
381
|
+
if parent_template_path:
|
|
382
|
+
break
|
|
383
|
+
|
|
384
|
+
if parent_template_path:
|
|
385
|
+
# Load the parent template with translation support
|
|
386
|
+
parent_content = load_template_with_translation(parent_template_path)
|
|
387
|
+
if parent_content:
|
|
388
|
+
# Create a template object from the translated content
|
|
389
|
+
parent_template = env.from_string(parent_content)
|
|
390
|
+
# We need to preserve the original template name for Jinja2 inheritance
|
|
391
|
+
parent_template.name = f"{page_name}.jinja2"
|
|
392
|
+
parent_template.filename = parent_template_path
|
|
393
|
+
else:
|
|
394
|
+
# Fallback to loading without translation if something went wrong
|
|
395
|
+
parent_template = parent_env.get_template(f"{page_name}.jinja2")
|
|
396
|
+
else:
|
|
397
|
+
# Fallback to original method if we can't find the file path
|
|
398
|
+
parent_template = parent_env.get_template(f"{page_name}.jinja2")
|
|
399
|
+
|
|
246
400
|
print(f"parent_template", parent_template)
|
|
247
401
|
child_templates = await load_plugin_templates(page_name, plugins)
|
|
248
402
|
parent_blocks = parent_template.blocks.keys()
|
|
@@ -307,7 +461,7 @@ async def render_combined_template(page_name, plugins, context):
|
|
|
307
461
|
return rendered_html
|
|
308
462
|
|
|
309
463
|
async def render_direct_template(template_path, context):
|
|
310
|
-
"""Render a template directly without combining with a parent template.
|
|
464
|
+
"""Render a template directly without combining with a parent template, with translation support.
|
|
311
465
|
|
|
312
466
|
Args:
|
|
313
467
|
template_path (str): Path to the template
|
|
@@ -320,6 +474,25 @@ async def render_direct_template(template_path, context):
|
|
|
320
474
|
context = context or {}
|
|
321
475
|
|
|
322
476
|
try:
|
|
477
|
+
# Check if we need to load with translation support
|
|
478
|
+
template_full_path = None
|
|
479
|
+
for loader in env.loader.loaders:
|
|
480
|
+
for template_dir in loader.searchpath:
|
|
481
|
+
potential_path = os.path.join(template_dir, template_path)
|
|
482
|
+
if os.path.exists(potential_path):
|
|
483
|
+
template_full_path = potential_path
|
|
484
|
+
break
|
|
485
|
+
if template_full_path:
|
|
486
|
+
break
|
|
487
|
+
|
|
488
|
+
if template_full_path:
|
|
489
|
+
# Load with translation support
|
|
490
|
+
content = load_template_with_translation(template_full_path)
|
|
491
|
+
if content:
|
|
492
|
+
template = env.from_string(content)
|
|
493
|
+
return template.render(**context)
|
|
494
|
+
|
|
495
|
+
# Fallback to normal template loading
|
|
323
496
|
template = env.get_template(template_path)
|
|
324
497
|
return template.render(**context)
|
|
325
498
|
except Exception as e:
|
|
@@ -327,7 +500,7 @@ async def render_direct_template(template_path, context):
|
|
|
327
500
|
return f"<h1>Error rendering template</h1><p>{str(e)}</p>"
|
|
328
501
|
|
|
329
502
|
async def render(page_name, context):
|
|
330
|
-
"""Render a template with plugin injections and
|
|
503
|
+
"""Render a template with plugin injections, overrides, and translation support.
|
|
331
504
|
If no parent template exists, tries to render a template directly from a plugin.
|
|
332
505
|
|
|
333
506
|
Args:
|
|
@@ -368,4 +541,3 @@ async def render(page_name, context):
|
|
|
368
541
|
trace = traceback.format_exc()
|
|
369
542
|
print(f"Error rendering {page_name}: {e}\n\n{trace}")
|
|
370
543
|
return f"<h1>Error Rendering Page</h1><p>{str(e)}</p><pre>{trace}</pre>"
|
|
371
|
-
|
|
@@ -141,7 +141,7 @@ def merge_json_arrays(data, partial=False):
|
|
|
141
141
|
pass
|
|
142
142
|
|
|
143
143
|
# Combine all parsed arrays into a single list
|
|
144
|
-
if arrays:
|
|
144
|
+
if len(arrays) > 0:
|
|
145
145
|
return list(chain.from_iterable(arrays))
|
|
146
146
|
|
|
147
147
|
# If all else fails, try the original json.loads as fallback
|
mindroot/migrate.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import logging
|
|
3
|
+
from .lib.plugins.manifest import create_default_plugin_manifest, _get_absolute_paths, _validate_manifest
|
|
4
|
+
|
|
5
|
+
# Setup logging
|
|
6
|
+
logger = logging.getLogger(__name__)
|
|
7
|
+
|
|
8
|
+
def migrate_plugin_manifest():
|
|
9
|
+
"""Migrate plugin_manifest.json from root to data/ directory if needed.
|
|
10
|
+
|
|
11
|
+
This function now delegates to the consolidated manifest handling logic.
|
|
12
|
+
"""
|
|
13
|
+
manifest_abs_path, root_manifest_abs_path, _ = _get_absolute_paths()
|
|
14
|
+
|
|
15
|
+
logger.info("Checking plugin manifest migration...")
|
|
16
|
+
logger.debug(f"Target manifest path: {manifest_abs_path}")
|
|
17
|
+
logger.debug(f"Source manifest path: {root_manifest_abs_path}")
|
|
18
|
+
|
|
19
|
+
# Check if target manifest already exists and is valid
|
|
20
|
+
is_valid, _ = _validate_manifest(manifest_abs_path)
|
|
21
|
+
if is_valid:
|
|
22
|
+
logger.info(f"Valid plugin manifest already exists at {manifest_abs_path}")
|
|
23
|
+
return
|
|
24
|
+
|
|
25
|
+
# Check if source manifest exists
|
|
26
|
+
source_exists = os.path.exists(root_manifest_abs_path)
|
|
27
|
+
if source_exists:
|
|
28
|
+
logger.info(f"Found manifest to migrate from {root_manifest_abs_path}")
|
|
29
|
+
else:
|
|
30
|
+
logger.info("No existing plugin manifest found to migrate")
|
|
31
|
+
|
|
32
|
+
# Use the consolidated manifest creation logic which handles migration
|
|
33
|
+
try:
|
|
34
|
+
create_default_plugin_manifest()
|
|
35
|
+
logger.info("Plugin manifest migration/creation completed successfully")
|
|
36
|
+
except Exception as e:
|
|
37
|
+
logger.error(f"Plugin manifest migration failed: {e}")
|
|
38
|
+
raise
|
|
39
|
+
|
|
40
|
+
def run_migrations():
|
|
41
|
+
"""Run all necessary migrations."""
|
|
42
|
+
logger.info("Running MindRoot migrations...")
|
|
43
|
+
try:
|
|
44
|
+
migrate_plugin_manifest()
|
|
45
|
+
logger.info("Migrations completed successfully")
|
|
46
|
+
except Exception as e:
|
|
47
|
+
logger.error(f"Migration failed: {e}")
|
|
48
|
+
# Don't raise here - let the system continue with default manifest
|
|
49
|
+
logger.warning("Continuing with default manifest due to migration failure")
|
mindroot/registry/data_access.py
CHANGED
|
@@ -6,7 +6,7 @@ class DataAccess:
|
|
|
6
6
|
self.data_dir = 'data'
|
|
7
7
|
self.models_file = os.path.join(self.data_dir, 'models.json')
|
|
8
8
|
self.providers_file = os.path.join(self.data_dir, 'providers.json')
|
|
9
|
-
self.plugins_file = 'plugin_manifest.json'
|
|
9
|
+
self.plugins_file = 'data/plugin_manifest.json'
|
|
10
10
|
self.equivalent_flags_file = os.path.join(self.data_dir, 'equivalent_flags.json')
|
|
11
11
|
self.preferred_models_file = os.path.join(self.data_dir, 'preferred_models.json')
|
|
12
12
|
|